🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿
- 欢迎大家:这里是CSDN,我的学习笔记、总结知识的地方,喜欢的话请三连,有问题可以私信🌳🌳🌳 您的点赞、关注、收藏、评论、私信是我最大的支持与鼓舞!!!🌻🌻🌻
泛型
泛型类型
- 泛型其实质就是将数据的类型参数化,通过为类、接口及方法设置类型参数来定义泛型。
- 泛型使一个类或一个方法可在不同类型的对象上进行操作。
- 泛型所操作的数据类型被指定为一个参数,这个参数被称为类型参数(type parameters)。
- 泛型类的定义是在类名后面加上,泛型接口的定义是在接口名后面加上,而泛型方法的定义是在方法的返回值前面加上,其头部定义分别如下:
泛型类的定义:[修饰符]class 类名<T>
泛型接口的定义:[public]interface 接口名<T>
泛型方法的定义:[public][static]<T> 返回值类型 方法名(T 参数)
a、类型参数名使用单个大写字母表示。
b、常用的类型参数名有:E(表示元素)、K(表示键)、N(表示数)、T(表示类型)、V(表示值)
c、在类和接口的声明中,可以有多个类型参数,但每个参数必须是唯一的。
实战演练
例:泛型类Node
publicclassNode<T>{privateT data;publicNode(){}publicNode(T data){this.data = data;}publicTgetData(){return data;}publicvoidsetData(T data){this.data = data;}publicvoidshowType(){System.out.println(" T的类型是:"+data.getClass().getName());}}
- 在使用泛型定义的类创建对象时,即在泛型类实例化时,也使用new运算符,但在类名后面需给出类型参数T的具体类型。
eg:Node<Integer> intNode =newNode<Integer>();Node<Integer> intNode =newNode<>();
- 在泛型类实例化的过程中,实际类型必须是引用类型, 不能用int、double或char等这样的基本类型来替换类型参数T。
实战演练
publicinterfaceEntry<K,V>{publicKgetKey();publicVgetValue();}publicclassPair<K,V>implementsEntry<K,V>{privateK key;privateV value;publicPair(K key,V value){this.key = key;this.value= value;}publicvoidsetKey(K key){this.key = key;}publicKgetKey(){return key;}publicvoidsetValue(V vlaue){this.value = value;}publicVgetValue(){return value;}publicstaticvoidmain(String[] args){Pair<Integer,String> p1 =newPair<>(20,"twenty");Pair<String,String> p2 =newPair<>("China","Beijing");System.out.println(p1.getValue());System.out.println(p2.getKey());}}
泛型方法
- 要定义泛型方法,只需将泛型的类型参数置于返回值前即可。
- 在Java中,任何方法都可声明为泛型方法。
- 只有声明了的方法才是泛型方法,泛型类中使用了泛型的成员方法并不是泛型方法。
- 泛型方法除了定义不同,调用时与普通方法一样。
- 推荐使用返回值类型和参数类型一致的泛型方法。
实战演练
例:Util.java
publicclassUtil{publicstatic<T>voidswap(T[] array,int i,int j){T temp = array[i];
array[i]= array[j];
array[j]= temp;}publicstatic<K,V>booleancompare(Pair<K,V> p1,Pair<K,V> p2){return p1.getKey().equals(p2.getKey())&&
p1.getValue().equals(p2.getValue());}publicstaticvoidmain(String[] args){Integer[] numbers ={1,3,5,7};Util.<Integer>swap(numbers,0,3);for(Integer n:numbers){System.out.println(n + “ ”);// 输出7 3 5 1}Pair<Integer,String> p1 =newPair<>(1,"apple");Pair<Integer,String> p2 =newPair<>(1,"apple");boolean same =Util.<Integer,String>compare(p1, p2);System.out.println(same);// 输出true}}
通配符(?)的使用
- 泛型类型本身是一个Java类型,为泛型类型传递不同的类型参数会产生不同的类型。
ArrayList<Object> list1 =newArrayList<Object>();ArrayList<String> list2 =newArrayList<String>();
- 尽管String是Object的子类,但ArrayList并不是ArrayList的子类型。
- 把ArrayList对象传递给一个需要ArrayList对象的方法,将会产生一个编译错误。
//打印传递列表的所有元素publicstaticvoidprintList(List<Object> list){for(Object element: list){System.out.println(element);}}
如何使上述方法可打印任意类型的列表?
通配符(?)List<?> list
实战演练
例:WildCardDemo.java
importjava.util.*;publicclassWildCardDemo{publicstaticvoidprintList(List<?> list){for(Object element : list)System.out.print(element+" ");}publicstaticvoidmain(String[] args){List<Integer> myList1 =newArrayList<>();List<String> myList2 =newArrayList<>();
myList1.add(3);
myList1.add(5);
myList2.add("three");
myList2.add("five");printList(myList1);System.out.println();printList(myList2);}}
有界类型参数
- 有时需要限制泛型类的类型参数,这就需要使用有界类型参数(bounded type parameter)。
- 有界类型分为上界和下界:
- 上界用extends指定:泛型类名<? extends T> 含义:传递的类型参数是T类或是继承类T的子类或是实现接口T的类类型
- 下界用super指定:泛型类名<? super T> 含义:传递的类型参数是类T或类T的父类的某种类型
实战演练
例1:
Demo11_1<? extendsList> x =null;
x =newDemo11_1<LinkedList>();//正确
x =newDemo11_1<ArrayList>();//正确
x =newDemo11_1<HashMap>();//编译错误
java.util. LinkedList 和java.util. ArrayList类都实现了List接口
例2:BoundedTypeDemo.java
importjava.util.*;publicclassBoundedTypeDemo{publicstaticdoublegetAverage(List<?extendsNumber> numberList){double total =0.0;for(Number number :numberList)
total += number.doubleValue();return total/numberList.size();}publicstaticvoidmain(String[] args){List<Integer> integerList =newArrayList<Integer>();
integerList.add(3);
integerList.add(30);
integerList.add(300);System.out.println(getAverage(integerList));// 111.0 List<Double> doubleList =newArrayList<>();
doubleList.add(5.5);
doubleList.add(55.5);System.out.println(getAverage(doubleList));// 30.5}}
继承泛型类与实现泛型接口
- 被定义为泛型的类或接口可被继承与实现。
- 泛型类的继承:
publicclassExtendClass<T1>{}classSubClass<T1,T2,T3>extendsExtendClass<T1>{}
- 泛型接口的实现:
interfaceFace<T1>`packageshujia_test1;publicclassPoint<TextendsNumber>{// 成员变量privateT x;privateT y;// 构造方法publicPoint(T x,T y){this.x = x;this.y = y;}// Getter 和 SetterpublicTgetX(){return x;}publicvoidsetX(T x){this.x = x;}publicTgetY(){return y;}publicvoidsetY(T y){this.y = y;}// translate 方法,将点移动到新的坐标publicvoidtranslate(T dx,T dy){// 由于 T 是 Number 的子类,我们可以安全地调用 doubleValue()double dxDouble = dx.doubleValue();double dyDouble = dy.doubleValue();// 这里我们假设 x 和 y 也应该是可以转换为 double 的 Number 类型double xDouble =this.x.doubleValue();double yDouble =this.y.doubleValue();// 进行计算double newX = xDouble + dxDouble;double newY = yDouble + dyDouble;// 现在我们需要将结果转换回 T 类型。但是,由于类型擦除,我们不能直接这样做。// 一个简单的解决方案是抛出一个异常或要求调用者提供一个转换函数。// 但为了演示,我们假设 T 是 Double(这在实际应用中可能不是一个好主意)if(this.x instanceofDouble&& dx instanceofDouble){this.x =(T)Double.valueOf(newX);// 这里有一个不安全的类型转换,但在某些情况下是可行的this.y =(T)Double.valueOf(newY);// 同样,这里也有一个不安全的类型转换}else{// 处理其他情况,比如当 T 不是 Double 时thrownewClassCastException("Unsupported operation for non-Double types.");}// 或者,更好的方法是接受精度损失,并始终将 x 和 y 存储为 double(如果适用)}// 主方法,用于演示publicstaticvoidmain(String[] args){// 创建Point<Integer>对象Point<Integer> pointInt =newPoint<>(1,2);System.out.println("Integer Point: ("+ pointInt.getX()+", "+ pointInt.getY()+")");
pointInt.translate(3,4);System.out.println("Translated Integer Point: ("+ pointInt.getX()+", "+ pointInt.getY()+")");// 创建Point<Double>对象Point<Double> pointDouble =newPoint<>(1.5,2.5);System.out.println("Double Point: ("+ pointDouble.getX()+", "+ pointDouble.getY()+")");
pointDouble.translate(3.5,4.5);System.out.println("Translated Double Point: ("+ pointDouble.getX()+", "+ pointDouble.getY()+")");}}
`
{}classSubClass<T1,T2 >implementsFace<T1>{}
🐱综合练习
定义一个泛型类Point,其中包含x和y两个类型为T的成员,定义带两个参数的构造方法,为x和y定义setter和getter,另外定义translate()方法将点移动到新的坐标。编写main()方法,创建Point对象和Point对象。
packageshujia_test1;publicclassPoint<TextendsNumber>{// 成员变量privateT x;privateT y;// 构造方法publicPoint(T x,T y){this.x = x;this.y = y;}// Getter 和 SetterpublicTgetX(){return x;}publicvoidsetX(T x){this.x = x;}publicTgetY(){return y;}publicvoidsetY(T y){this.y = y;}// translate 方法,将点移动到新的坐标publicvoidtranslate(T dx,T dy){// 由于 T 是 Number 的子类,我们可以安全地调用 doubleValue()double dxDouble = dx.doubleValue();double dyDouble = dy.doubleValue();// 这里我们假设 x 和 y 也应该是可以转换为 double 的 Number 类型double xDouble =this.x.doubleValue();double yDouble =this.y.doubleValue();// 进行计算double newX = xDouble + dxDouble;double newY = yDouble + dyDouble;// 现在我们需要将结果转换回 T 类型。但是,由于类型擦除,我们不能直接这样做。// 一个简单的解决方案是抛出一个异常或要求调用者提供一个转换函数。// 但为了演示,我们假设 T 是 Double(这在实际应用中可能不是一个好主意)if(this.x instanceofDouble&& dx instanceofDouble){this.x =(T)Double.valueOf(newX);// 这里有一个不安全的类型转换,但在某些情况下是可行的this.y =(T)Double.valueOf(newY);// 同样,这里也有一个不安全的类型转换}else{// 处理其他情况,比如当 T 不是 Double 时thrownewClassCastException("Unsupported operation for non-Double types.");}// 或者,更好的方法是接受精度损失,并始终将 x 和 y 存储为 double(如果适用)}// 主方法,用于演示publicstaticvoidmain(String[] args){// 创建Point<Integer>对象Point<Integer> pointInt =newPoint<>(1,2);System.out.println("Integer Point: ("+ pointInt.getX()+", "+ pointInt.getY()+")");
pointInt.translate(3,4);System.out.println("Translated Integer Point: ("+ pointInt.getX()+", "+ pointInt.getY()+")");// 创建Point<Double>对象Point<Double> pointDouble =newPoint<>(1.5,2.5);System.out.println("Double Point: ("+ pointDouble.getX()+", "+ pointDouble.getY()+")");
pointDouble.translate(3.5,4.5);System.out.println("Translated Double Point: ("+ pointDouble.getX()+", "+ pointDouble.getY()+")");}}
博主用心写,读者点关注,互动传真情,知识不迷路。
版权归原作者 倾听一世,繁花盛开 所有, 如有侵权,请联系我们删除。