反射
在框架的设计中很多都用到了反射,比如spring中我们在applicationContext.xml中配置类,通过反射+工厂模式得到类的实例,就可以操作类了——操作一个类可以分为操作属性,构造方法,普通方法。
反射的原理
我们编写的Java文件是xxx.java保存在硬盘上的,只是.java是无法运行的,需要编译成.class文件,JVM再将这个class文件通过类加载器加载到内存中,这个class文件在内存中是以Class类的形式表示。所以,使用反射的第一步是得到Class类(因为.java文件和没有加载到内存的.class文件计算机都是无法操作的),得到Class类就可以操作类的内容了(属性,构造方法,普通方法)
属性类:Field 构造方法类:Constructor 普通方法类:Method
获得Class类
方法一:类名,class
Class clazz1=Person.class;
方法二:实例.getClass()
Class clazz2=new Person().getClass();
方法三:Class.forName("类的全路径") 最常用
Class clazz3=Class.forName("cn.lynu.model.Person");
实例化对象
如果不使用new的方式,如何获得一个类的实例化? 那就是使用反射的newInstance()方法
Class clazz3=Class.forName("cn.lynu.model.Person");
Person person=(Person)clazz3.newInstance();
使用反射操作无参构造
/**
* 反射操作无参构造函数
* @throws Exception
*/
@Test
public void fun1() throws Exception{
Class clazz = Class.forName("cn.lynu.model.Person"); //得到class类
Person p1 = (Person) clazz.newInstance(); //通过反射得到实例
p1.setName("lz");
System.out.println(p1.getName());
}
这里我通过反射得到Person类的实例p1,通过p1给Name属性赋值
使用反射操作有参构造
主要使用的是getConstructor(构造方法参数的Class类)获得Constructor类,再通过Constructor类实例化,实例化的过程就可以给值了
/**
* 反射操作有参构造函数
* @throws Exception
*/
@Test
public void fun2() throws Exception{
Class clazz = Class.forName("cn.lynu.model.Person");
//使用getConstructor(可变参数 参数类型的class类)得到构造函数类
Constructor constructor = clazz.getConstructor(String.class,int.class);
Person p2 = (Person) constructor.newInstance("lz",21);
System.out.println(p2.getName()+" "+p2.getAge());
}
使用反射操作属性
主要使用的是getDeclaredField("属性名")得到Field类,通过Field类设置属性的值(set()方法),对了,不要忘了使用 setAccessible(true); 就可以操作私有的属性(属性一般都是私有的)
/**
* 反射操作属性
* @throws Exception
*/
@Test
public void fun3() throws Exception{
Class clazz = Class.forName("cn.lynu.model.Person");
//通过getDeclaredField(属性名)得到属性类
Field age = clazz.getDeclaredField("age");
//私有属性需要设置setAccessible(true),必须在设置参数之前
age.setAccessible(true);
//反射实例化对象
Person p3 = (Person) clazz.newInstance();
age.set(p3, 21); //设置参数
//System.out.println(name.get(p3));
System.out.println(p3.getAge());
}
使用反射操作普通方法
主要使用getDeclaredMethod("方法名","参数Class类")获得Method类,再通过Method类的invoke()方法给方法赋值。如果操作的是私有的方法也需要设置setAccessible(true); 。当操作的是静态的方法时候,因为静态方法调用的方式是 类名.方法名,所以使用反射操作静态方法的时候不需要实例 m1.invoke(null,"lz");
/**
* 反射操作普通函数
* @throws Exception
*/
@Test
public void fun4() throws Exception{
Class<?> clazz = Class.forName("cn.lynu.model.Person");
//使用getDeclaredMethod(方法名,方法参数Class类)得到方法类
Method name = clazz.getDeclaredMethod("setName", String.class);
Person p4 = (Person) clazz.newInstance(); //反射实例化
name.invoke(p4, "lz"); //给普通方法设置参数
System.out.println(p4.getName());
}
泛型
泛型多用于集合之上,例如这样的场景:将一个字符串类型的值放入到集合中,这个值就会失去其类型,统一为Object类型,而后再将这个值取出进行类型转换,就容易出现类型转换异常,因为Object可以转换为任何类型,要解决这样的问题就需要使用泛型
泛型语法
一般情况下我们使用T表示泛型,但这不是强制要求。注意:给这个T赋具体类型的时候要使用基本类型的包装类
- 在集合上使用 集合<具体类型>
- 在返回值和形参上使用
- 在类上使用 class A<T>
- 在方法上使用 public <T> void fun1(T t1){} public <T> T fun2(T t1,T t2){}
- 在局部变量(因为要使用T,就需要在已定义过的地方,所以可以在泛型方法和泛型类的成员属性使用)上使用
public <T> void fun1(){
T abc;
}
class a<T>{
T bcd;
}
泛型的使用
下面是一个使用泛型进行数组元素颠倒顺序的例子,使用泛型增加了通用性
import java.util.Arrays;
public class TestDemo3 {
public static void main(String[] args) {
Integer[] arr1={1,2,3,4,5,6};
System.out.println(Arrays.toString(arr1));
reverse(arr1);
System.out.println(Arrays.toString(arr1));
System.out.println("==================");
String[] arr2={"aaa","bbb","ccc","eee","fff"};
System.out.println(Arrays.toString(arr2));
reverse(arr2);
System.out.println(Arrays.toString(arr2));
}
/**
* 使用泛型颠倒数组元素
*/
public static <T> void reverse(T[] arr){
for(int i=0;i<(arr.length/2);i++){
T temp=arr[i];
arr[i]=arr[arr.length-1-i];
arr[arr.length-1-i]=temp;
}
}
}
reverse()方法使用泛型,所以我们不管数组到底是什么类型的,都可以完成元素的颠倒操作
区分泛型类中的方法和泛型方法
泛型类中的方法:
class A<T>{
public T fun1(T t1){} //不是泛型方法,只是泛型类中的一个方法
}
泛型方法:
public <T> T fun1(T t1){} //泛型方法
这俩个fun1方法表达意思是不一样的,泛型方法与泛型类没什么关系,泛型方法不一定要在泛型类中,泛型类中也不一定都是泛型方法
泛型的继承和实现
泛型可以认为不可以继承,子类不是泛型类:
class A<T>{}
class AA1 extends A<String> {} //这个AA1不是泛型类,只是其父类A是泛型类
这个例子中AA1不是泛型类,只是其父类泛型类,AA1在声明的时候需要指定父类泛型的具体类型
子类是泛型类 :
class A<T>{}
class AA2<T> extends A<T> {} //子类也是泛型类
这里子类AA2是泛型类,继承的父类A也是泛型类,子类也是泛型类情况下,可以实例化AA2的时候再指明泛型的具体类型
public class TestDemo5{
public static void main(String[] args) {
AA1 aa1=new AA1();
aa1.fun2(t1); //t1为Integer类型
AA2<String> aa2=new AA2<String>(); //泛型类在实例化时指定类型
aa2.fun2(t1); //t1为String类型
}
}
class A<T>{
private T ab;
public void fun1(){}
public void fun2(T t1){}
public void fun3(T t1,T t2){}
}
class AA1 extends A<Integer>{ //继承于泛型类A,AA1不是泛型类
}
class AA2<T> extends A<T>{ //继承于泛型类A,AA2是泛型类
}