目录
泛型
在类定义时不明确类型,使用时明确类型,在编译阶段检查设置的值是否是同一类型
public class Point<T> {
private T x;
private T y;
}
public class PointNew<T,E> {
private T x;
private E y;
}
//T称为类型参数,<>里面可以是任意参数,
public static void main(String[] args) {
Point<String> p1 = new Point<>();
PointNew<String,Integer> p2 = new PointNew<>();
}
定义泛型对象时,只能使用类。基本数据类型不能保存到泛型中,需要使用对应的包装类。
泛型方法
//方法定义前面有<>,才是泛型方法
public <E> E func(E e) {
return e;
}
//这不是泛型方法
public E test(E e) {
return e;
}
可以定义在普通类中,但是T是Object类
泛型方法始终以自己的类型参数为准,与泛型类中的T无关;若泛型类中存在了泛型方法,推荐定义为不同的类型参数,不会造成异义。
泛型接口
接口使用泛型声明,子类在实现该接口时:
- 继续保留泛型
- 子类明确当前的泛型
通配符
?
方法参数中传入泛型接口类型的对象,<?>表示:该方法可以接受该接口的任意形态(<>内什么类型都可以)。这样的方法内部,不可以使用传入对象的set方法,因为不知道该对象的类型是什么。
? extends 某个类(泛型的上限为某个类)
-
例如:? extends Number,表示传入的接口对象,其接口的<>内的类型为Number类及其子类。方法内部仍然不可以使用传入对象的set方法,因为向下转型不一定成功
-
也可以在泛型类的定义中使用
? super 某个类(泛型的下限为某个类)
-
只能接收该类及其父类
-
明确下限类型,无论传入对象是什么类型,都是下限类型的父类(或其本身),此时设置一个下限类型的值,可以通过自动的向上转型成功更改传入对象的值。即:可以使用set方法
-
下限通配符只能用在方法内部,不能在类中定义
类型擦除
泛型信息只存在于编译阶段,进入JVM后,会将所有和泛型信息相关的信息都擦除。
若没有规定泛型上限。则所有泛型信息都擦除为Object类,若规定了泛型上限,则擦除为相应的泛型上限类型。
经过javac,把*.java文件编译为*.class文件之后,泛型就没有了。
反射
在JVM运行时:
-
对于JVM中的任何一个类,都能动态获取该类的所有属性和方法;
-
对于JVM中任何一个对象,都能动态调用该对象的属性和方法。
动态获取信息以及调用对象机制称为反射机制。
反射是一切框架的基础
运行时类型:
编译时类型:
//运行时明确该引用到底是什么类型就可以通过反射机制
Person p = new Student();
//p的编译时类型,Person
//p的运行时类型,Student
反射相关的类
都在java.lang.reflect中
Class类
使用class关键字、数组、接口编译后生成的class文件就对应唯一一个Class类的对象,由JVM产生,根据这个对象来反射操作类
- 利用反射机制的第一步:获取该类的class对象(全局唯一)
- 调用Class.forName(类的全名称:包名.类名)
- 类名称.class
- 通过该类的任意对象的getClass()方法
Field类
代表类的成员变量/类属性
//Field类对象的get和set方法
//通过obj对象获取该对象相关属性的值,若为静态属性,传入null
public Object get(Object obj)
//通过obj对象设置该对象相关属性的值,设置的值为value;若修改的属性是静态属性,则传入null
public void set(Object obj, Object value)
Method类
代表类的方法
public Object invoke(Object obj, Object...args)
//参数列表的第一个值obj代表通过哪个对象调用该方法,若调用静态方法,则obj传入null
//后面的args代表被调用该方法的参数类型,没有参数就不写
Constructor类
代表类的构造方法
通过反射调用类的构造方法
不加declared:获取该类中声明为public权限的构造方法
加declared:获取所有的构造方法
//通过构造方法,反射产生对象
setAccessible(true) 破坏封装性