<T extends Number>
指定了参数类型。
public class Test0 {public static <T extends Number> double add(T a,T b) {return a.doubleValue()+b.doubleValue();}public static void main(String[] args) {System.out.println(Test0.add(1.0f,2l));}
}
运行结果
3.0
无需强制转换
public class Test2 {static class Message<T> {private T t;public T getT() {return t;}public void setT(T t) {this.t = t;}}public static void main(String[] args) {Message<String> message = new Message<>();message.setT("abc");System.out.T());}
}
运行结果
abc
public class Test3 {static class Entry<K,V> {private K key;private V val;public K getKey() {return key;}public void setKey(K key) {this.key = key;}public V getVal() {return val;}public void setVal(V val) {this.val = val;}}public static void main(String[] args) {Entry<Integer,String> entry = new Entry<>();entry.setKey(200);entry.setVal("成功");System.out.Key()+","Val());}
}
运行结果
200,成功
public class Test4 {interface Response<T> {public T getVar();}static class ResponseImpl<T> implements Response<T> {private T var;@Overridepublic T getVar() {return var;}public void setVar(T var) {this.var = var;}public ResponseImpl(T var) {this.var = var;}}public static void main(String[] args) {Response<String> response = new ResponseImpl<>("abc");System.out.Var());}
}
运行结果
abc
<T>
声明泛型方法持有T
public class Test5 {public static <T> void print(T[] arr) {for(T t:arr) {System.out.print(t+"t");}}public static void main(String[] args) {Test5.print(new String[]{"a","b","c"});}
}
运行结果
a b c
public class Test6 {public static <T,V> void print(T[] arr,V[] arr2) {for(T t:arr) {System.out.print(t+"t");}for(V v:arr2) {System.out.print(v+"t");}}public static void main(String[] args) {Test6.print(new String[]{"a","b","c"},new Integer[]{1,2,3,4,5});}
}
运行结果
a b c 1 2 3 4 5
通过泛型与反射创建对象
public class Test7 {public static <T> T getInstance(Class<T> c) {T t = null;try {t = c.newInstance();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return t;}public static void main(String[] args) throws ClassNotFoundException {Object instance = Instance(Class.forName(ic.O"));System.out.Class());}
}
运行结果
ic.O
在调用泛型方法时,可以指定类型,此时编译器会校验参数类型
public class Test8 {static class A {}static class B extends A {}public void putA(A a ){}public void putB(B b) {putA(b);System.out.println("自动进行类型转换,里氏替换");}public static void main(String[] args) {Test8 test8 = new Test8();test8.putB(new B());}
}
在这个方法可以正常调用,因为编译器会识别 putA(b);
的参数类型是B。
问题二
但是如果是List类型就会报错哦.因此此处是隐含的类型转换。
用泛型解决
<? extends A>
表示该类型参数可以是A(上边界)或者A的子类类型。编译通过。
public void putA(List<? extends A> lista ){}public void putB(List<B> listb) {putA(listb);System.out.println("自动进行类型转换,里氏替换");}
extends 关键字声明了类型的上界;super 关键字声明了类型的下界。
public class Test11 {static class Point<T> {}public static void main(String[] args) {Point<? super Number> p1 = new Point<Object>();Point<? extends Number> p2 = new Point<Integer>();}
}
<T extends Staff & Passenger>
要求泛型必须同时实现两个接口。
public class Test12 {interface Staff{int getSalary();}interface Passenger{boolean isStanding();}static class Person implements Staff,Passenger {@Overridepublic int getSalary() {return 11110;}@Overridepublic boolean isStanding() {return false;}}//工资低于2500元的上斑族并且站立的乘客车票打8折public static <T extends Staff & Passenger> void discount(T t){Salary()<2500 && t.isStanding()){System.out.println("恭喜你!您的车票打八折!");}}public static void main(String[] args) {discount(new Person());}
}
Java在语法上支持泛型,但是在编译阶段会进行所谓的“类型擦除”(Type Erasure),将所有的泛型表示(尖括号中的内容)都替换为具体的类型(其对应的原生态类型),就像完全没有泛型一样。
实验证明,l1 和 l2 的类型相同。
public class Test13 {public static void main(String[] args) {List<String> l1 = new ArrayList<>();List<Integer> l2= new ArrayList<>();System.out.Class());System.out.Class());}
}
运行结果
class java.util.ArrayList
class java.util.ArrayList
通过反射,仍然可以向泛型类里存放字符串。
public class Test14 {public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {ArrayList<Integer> l1 = new ArrayList<>();l1.add(42);l1.getClass().getMethod("add",Object.class).invoke(l1,"abc");System.out.println(l1);}
}
运行结果
[42, abc]
由于引用类型的声明没有声明为泛型,实际上什么都可以往里存。
所以泛型的检查是针对引用的,而无关它真正引用的对象。
public class Test16 {public static void main(String[] args) {List ls = new ArrayList<String>();ls.add("ba");ls.add(1);System.out.println(ls);}
}
泛型就是需要明确关系,如果参数是可以继承的,但是仍然不允许传递。
因为泛型类中的泛型参数的实例化是在定义对象的时候指定的,而静态变量和静态方法不需要使用对象来调用。因此是错误的。
但是静态方法居然可以通过,请注意此T是方法声明,非类定义的泛型T。
public static <T> T getT(){return null;}
public class Test20<T> {public static void main(String[] args) {Test20<Integer> genericType = new Test20<Integer>() {};Type superclass = Class().getGenericSuperclass();Type type = ((ParameterizedType) superclass).getActualTypeArguments()[0];System.out.println(type);//class java.lang.String}
}
结果:
class java.lang.Integer
看这个方法,D继承了C,覆写了C的方法。
public class Test18 {static class C<T>{private T val;public T getVal() {return val;}public void setVal(T val) {this.val = val;}}static class D extends C<String>{@Overridepublic String getVal() {Val();}@Overridepublic void setVal(String val) {super.setVal(val);}}public static void main(String[] args) {C c = new C();c.setVal(new Object());D d = new D();d.setVal(new Object());}
}
但是注意,C方法在编译期中会被擦除泛型参数,变为Object,因此D的get、set方法由于入参和返回值不一样,就不是对C的覆写了。
真的是这样吗?
运行显示,d不允许d.setVal(new Object());
。可是我们之前的思路,应当父类的方法并没有被覆盖啊,是可以调用父类的方法的啊.
问题在于虚拟机的优化实现。
运行javap -c命令查看字节码,发现jvm帮助我们实现了子类的方法,一共有两套get和set方法,以匹配父类方法。
当然我们自己是无法这样实现的,以为编译不会通过,因为jvm违反了重载的约束,仅仅返回值不同就定义了多个方法。
1.Java中的泛型是什么 ? 使用泛型的好处是什么?
泛型是一种参数化类型的机制。它可以使得代码适用于各种类型,从而编写更加通用的代码,例如集合框架。
泛型是一种编译时类型确认机制。它提供了编译期的类型安全,确保在泛型类型(通常为泛型集合)上只能使用正确类型的对象,避免了在运行时出现ClassCastException。
2.Java的泛型是如何工作的 ? 什么是类型擦除 ?
泛型的正常工作是依赖编译器在编译源码的时候,先进行类型检查,然后进行类型擦除并且在类型参数出现的地方插入强制转换的相关指令实现的。编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。例如List在运行时仅用一个List类型来表示。为什么要进行擦除呢?这是为了避免类型膨胀。
3.什么是泛型中的限定通配符和非限定通配符 ?
限定通配符对类型进行了限制。有两种限定通配符,一种是<? extends T>它通过确保类型必须是T的子类来设定类型的上界,另一种是<? super T>它通过确保类型必须是T的父类来设定类型的下界。泛型类型必须用限定内的类型来进行初始化,否则会导致编译错误。另一方面<?>表示了非限定通配符,因为<?>可以用任意类型来替代。
4.List<? extends T>和List <? super T>之间有什么区别 ?
List<? extends T>可以接受任何继承自T的类型的List,而List<? super T>可以接受任何T的父类构成的List。例如List<? extends Number>可以接受List或List。
泛型是一种参数化类型的机制。它可以使得代码适用于各种类型,从而编写更加通用的代码,例如集合框架。
泛型是一种编译时类型确认机制。它提供了编译期的类型安全,确保在泛型类型(通常为泛型集合)上只能使用正确类型的对象,避免了在运行时出现ClassCastException。
java基础 系列在github上有一个开源项目,主要是本系列博客的demo代码。
如果您对软件开发、机器学习、深度学习有兴趣请关注本博客,将持续推出Java、软件架构、深度学习相关专栏。
您的支持是对我最大的鼓励。
本文发布于:2024-01-31 09:19:50,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170666399127480.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |