Java泛型
为什么需要泛型
List list = new ArrayList();
list.add("CSDN_SEU_Cavin");
list.add(100);
for (int i = 0; i < list.size(); i++) {
String name = (String) list.get(i); //取出Integer时,运行时出现ClassCastException异常
System.out.println("name:" + name);
}
list 集合中加入了一个字符类型的值和Integer类型的值[因为list默认类型为Object类型所以这样写合法]
为了解决这个问题,泛型才会出现
泛型的使用
List<String> list = new ArrayList<String>()
这样以后,list.add(100)时,引起编译错误。
通过List<String>
,直接限定了list集合中只能含有String类型的元素,从而在上例中的第5行中,无须进行强制类型转换,因为集合能够记住其中元素的类型信息,编译器已经能够确认它是String类型了。
泛型只在编译阶段有效
命名规则
E - Element (通常代表集合类中的元素)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. – 第二个,第三个,第四个类型参数……
注意,父类定义的类型参数不能被子类继承。
- 也可以同时声明多个类型变量,用逗号分割,例如:
public interface Pair<K, V> {
public K getKey();
public V getValue();
}
public class OrderedPair<K, V> implements Pair<K, V> {
private K key;
private V value;
public OrderedPair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
}
- 创建了OrderedPair对象的两个实例
Pair<String,Integer> p1 = new OrderedPair<String, Integer>("Even", 8);
Pair<String,String> p2 = new OrderedPair<String, String>("hello", "world");
//也可以将new后面的类型参数省略,简写为:
//Pair<String,Integer> p1 = new OrderedPair<>("Even", 8);
//也可以在尖括号内使用带有类型变量的类型变量,例如:
OrderedPair<String,Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>(...));
- 在方法中也可是使用泛型参数,并且该参数的使用范围仅限于方法体内
public class Util {
//该方法用于比较两个Pair对象是否相等。
//泛型参数必须写在方法返回类型boolean之前
public static <K, V> boolean compare(Pair<K,V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey())&&
p1.getValue().equals(p2.getValue());
}
}
Pair<Integer,String> p1 = new Pair<>(1, "apple");
Pair<Integer,String> p2 = new Pair<>(2, "pear");
boolean same = Util.<Integer, String>compare(p1, p2);
//实际上,编译器可以通过Pair当中的类型来推断compare需要使用的类型,所以可以简写为:
// boolean same= Util. compare(p1, p2);
泛型类的继承
- Integer是Object的子类
- Integer是Number的子类
- Double是Number的子类
- 容易混淆的
/该方法接受的参数类型为Box<Number>
public void boxTest(Box<Number> n) {
……
}
//下面两种调用都会报错
boxTest(Box<Integer>);
boxTest(Box<Double>);
虽然Integer和Double都是Number的子类,但是Box与Box并不是Box的子类,不存在继承关系。Box与Box的共同父类是Object。
通配符
public void boxTest(Box<Number> n){
……
}
该方法只能接受 Box<Number>
这种类型的参数,因此用到了通配符
- 为了该方法可以接受Number以及它的任何子类
public void boxTest(Box<? extends Number> n){
……
}
“ ? extends Number ”就代表可以接受Number以及它的子类作为参数。这种声明方式被称为上限通配符(upper bounded wildcard)。
- 希望该方法可以接受Integer,Number以及Object类型的参数
public void boxTest(Box<? super Integer> n){
……
}
“ ? super Integer ”代表可以接受Integer以及它的父类作为参数。这种声明方式被称为下限通配符(lower bounded wildcard)。
- 如果类型参数中既没有extends 关键字,也没有super关键字,只有一个?,代表无限定通配符(Unbounded Wildcards)。
- 通常在两种情况下会使用无限定通配符:
- 如果正在编写一个方法,可以使用Object类中提供的功能来实现
- 代码实现的功能与类型参数无关,比如List.clear()与List.size()方法,还有经常使用的Class
例子:
上限通配符、下限通配符、无限定通配符之间的关系:
java的反射机制
什么是反射机制
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法
;对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射机制能做什么
反射机制主要提供了以下几个功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法
- 生成动态代理
具体功能实现
反射机制获取类有三种方法,我们来获取Employee类型
//第一种方式:
Classc1 = Class.forName("com.app.XXX.Employee");
//第二种方式:
//java中每个类型都有class 属性.
Classc2 = Employee.class;
//第三种方式:
//java语言中任何一个java对象都有getClass 方法
Employee e = new Employee();
Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)
获取所有的方法:getMethods();
-
Method[] methods = class1.getMethods();
获取所有实现的接口:getInterfaces();
Class<?>[] in = class1.getInterfaces();
获取父类:getSuperclass();
-
Class<?> superclass = class1.getSuperClass();
获取所有的构造函数:getConstructors();
Constructor<?>[] constructors = class1.getConstructors() ;
获取所有的属性:getDeclaredFields();
Field[] field = class1.getDeclaredFields();
- 可以看出属性的修饰符是: private(会变) , 数据类型:String (会变),名字:id/name(会变)
getDeclaredFields();
和getFields();
的区别
-
getDeclaredFields()
:获得某个类的所有申明的字段,即包括public、private和proteced,但是不包括父类的申明字段。 -
getFields()
:获得某个类的所有的公共(public)的字段,包括父类。
field.setAccessible(true);
===>例:private 类型 无法做出修改 所以设置这个 就可以了
- 打破封装 实际上setAccessible是启用和禁用访问安全检查的开关,并不是为true就能访问为false就不能访问
- 由于JDK的安全检查耗时较多.所以通过setAccessible(true)的方式关闭安全检查就可以达到提升反射速度的目的
创建对象:获取类以后我们来创建它的对象,利用newInstance:
//创建类
Class<?> class1 = Class.forName("com.app.Person");
//创建实例化:相当于 new 了一个对象
Object object = class1.newInstance() ;
//向下转型
Person person = (Person) object ;
总结
- 首先根据传入的类的全名来创建Class对象
- Class c = Class.forName(“className”);//className必须为全名 也就是包含包名,比如:cn.netjava.pojo.UserInfo
- Object obj = c.newInstance();//创建对象的实例
有了对象之后 想要什么信息 就可以得到什么信息了
- Class类提供了四个public方法,用于获取某个类的构造方法。
-
Constructor getConstructor(Class[] params)
根据构造函数的参数,返回一个具体的具有public属性的构造函数(根据指定参数获得public构造方法) -
Constructor[] getConstructors()
返回所有具有public属性的构造函数数组(获得public的所有构造方法) -
Constructor getDeclaredConstructor(Class[] params)
根据构造函数的参数,返回一个具体的构造函数(根据指定参数获得public和非public的构造方法) -
Constructor[] getDeclaredConstructors()
返回该类中所有的构造函数数组(获得public的所有构造方法)
- 四种获取成员方法的方法
-
Method getMethod(String name, Class[] params)
根据方法名和参数,返回一个具体的具有public属性的方法(根据方法名 参数类型获得方法) -
Method[] getMethods()
返回所有具有public属性的方法数组(获取所有的public方法) -
Method getDeclaredMethod(String name, Class[] params)
根据方法名和参数,返回一个具体的方法(根据方法名和参数类型,获得public和非public的方法) -
Method[] getDeclaredMethods()
返回该类中的所有的方法数组(不分public和非public属性)
- 四种获取成员属性的方法
-
Field getField(String name)
根据变量名,返回一个具体的具有public属性的成员变量(根据变量名得到相应的public变量) -
Field[] getFields()
返回具有public属性的成员变量的数组(获得类中所有public的方法) -
Field getDeclaredField(String name)
根据变量名,返回一个成员变量(根据方法名获得public和非public的变量) -
Field[] getDelcaredField()
返回所有成员变量组成的数组(获取类中所有的public和非public的方法)
“`
利用反射机制能获得什么信息