文章目录
1、反射的介绍
(1)Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行 期 借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。
(2)加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。
2、反射API
2.1、获取类对应的字节码的对象(三种)
1.调用某个类的对象的getClass()方法,即:对象.getClass();
User user = new User();
Class uClass= user.getClass();
- 调用类的class属性类获取该类对应的Class对象,即:类名.class
Class userClass = User.class;
- 使用Class类中的forName()静态方法(最安全,性能最好)即:Class.forName(“类的全路径”)
Class aClass = Class.forName("com.ref.User");
2.2、Class类的常用方法
//返回指定类名namegClass对象
1.static glassforName(String name)
//返回指定类名namegClass对象
2.Object newlnstance()
//调用缺省构造函数,返回Class对象的一个实例
3.getName()
//返回此Class对象所表示的实体(类,接口,数组类或void)的名称。
4.Class getSuperClass()
//返回当前Class对象的父类的Class对象获取当前Class对象的接口
5.Class[] getinterfaces()
//返回该类的类加载器
6.ClassLoader getClassLoader()
//返回一个包含某些Constructor对象的数组
7.Constructor[]getConstructors()
//返回一个Method对象,此对象的形参类型为paramType
8.Method getMothed(String name,Class.. T)
//返回Field对象的一个数组
9.Field[] getDeclaredFields()
2.3、哪些类型可以有class对象
1.class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
2.interface:接口
3. [ ]:数组
4. enum:枚举
5. annotation:注解 @interface
6. primitive type:基本数据类型
7. void
Class c1 = Object.class; //类
Class c2 = Comparator.class; //接口
Class c3 = String[].class; //数组
Class c4 = int[][].class; //二维数组
Class c5 = Override.class; //注解
Class c6 = ElementType.class; //枚举
Class c7 = Integer.class; //基本数据类型
Class c8 = void.class; //void
Class c9 = Class.class; //Class
运行结果
class java.lang.Object
interface java.util.Comparator
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
Process finished with exit code 0
3、反射在类的应用
3.1、创建类对象
package com.ref;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private Integer id;
//普通方法
public void say(){
System.out.println("卷起来,伙计们");
}
public void play(){
System.out.println("玩起来,伙计们");
}
}
3.2、获取class对象
//通过包名获取class对象
Class<?> aClass = Class.forName("com.ref.User");
//通过class类获取class对象
Class<User> userClass = User.class;
//通过User类的对象获取class对象
Class<? extends User> aClass1 = new User().getClass();
//返回值为true 验证了一个类只有一个class对象
System.out.println(aClass.hashCode()==userClass.hashCode());
//打印的是User类对应的字节码对象
System.out.println(aClass);//class com.ref.User
//获取User类对应的字节码对象userClass的名字
System.out.println(userClass.getName());//com.ref.User
//通过User类对应的字节码对象,获取User类的类名
System.out.println(aClass.getSimpleName());//User
//通过User类对应的字节码对象,获取User类对应的包对象
System.out.println(aClass.getPackage());//package com.ref
//通过User类对应的字节码对象,先获取User类对应的包对象,再获取这个包对象的名字
System.out.println(aClass.getPackage().getName());//com.ref
3.3、获取类的属性并设置属性值
Class c1 = User.class;
Field[] fields = c1.getFields();//获取public的属性值
for(Field field:fields){
//属性都是private修饰 输出为null
System.out.println(field);
}
fields = c1.getDeclaredFields();
for(Field field:fields){
//输出: private java.lang.String com.ref.User.name
// private java.lang.Integer com.ref.User.id
System.out.println(field);
}
Field name = c1.getDeclaredField("name");
//不能直接操作因为是**私有属性**,我们需要关闭程序的安全检测,属性或者方法的setAccessible(true) .
name.setAccessible(true);
name.set(user,"神仙");
//输出:神仙
System.out.println(user.getName());
3.4、调用普通方法
Class c1 = User.class;
//通过反射调用普通方法
User user =(User)c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getDeclaredMethod("setName", String.class);
//invoke :激活的意思
//(对象名,"方法的值")
setName.invoke(user,"大学生");
//输出:大学生
System.out.println(user.getName());
4、创建对象的5种方式
new关键字
User user = new User();
Class.newInstance方法
//通过反射获取类对象
Class<User> userClass = User.class;
//通过类对象创建
User user = userClass.newInstance();
Constructor.newInstance方法
Class<User> userClass = User.class;
//通过构造器创建对象
Constructor<User> declaredConstructor = userClass.getDeclaredConstructor();
User user = declaredConstructor.newInstance("张三", 20);
Clone方法
无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去,用clone方法创建对象并不会调用任何构造函数。 要使用clone方法,我们必须先实现Cloneable接口并复写Object的clone方法。
public class User implements Cloneable {
private String name;
private Integer id;
@Override
public User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
User user = new User();
Object clone = user.clone();
//false
System.out.println(clone == user);
}
}
反序列化
1、通过序列化,将对象的状态写在流里面:
先构造一个对象流ObjectOutputStream oss,使用oos的writeObject的方法将实例对象user1的状态写到流(字节流文件user1.ser)里面。
2、根据需要把该流读取出来重新构造一个相同的对象:
先构造一个对象流ObjectInputStream ois读取字节流文件user1.ser,使用ois的readObject的方法重新构造一个相同的对象user1。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private String name;
private Integer id;
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user1.ser"));
User user1 = new User("张三",10);
oos.writeObject(user1);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user1.ser"));
User user2 = (User) ois.readObject();
System.out.println("user2"+user2);
ois.close();
}
}