目录
反射
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
class类
java程序经过了运行和编译两个过程。程序编译之后生成class文件(class文件是二进制文件),class文件经过JVM的类加载器加载进入内存,JVM的解析器对内存的class文件进行解析,产生机器可以识别的机器语言。
类加载器加载的过程中,会创建Class类的实例java.lang.Class,通过这个对象,可以访问到类的任何属性,而反射就可以做到这一点。
如何获得Class对象
class Person {
private String name;
public int age;
private Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("这是有两个参数的私有的构造方法 " + name + age);
}
public Person(String name) {
this.name = name;
System.out.println("这是有一个参数的公开的构造方法" + name + age);
}
public Person() {
System.out.println("这是没有参数的公开的构造方法");
}
private void print(String name, int age) {
System.out.println("这是有两个参数的私有的普通方法" + name + age);
}
public void print() {
System.out.println("这是没有参数的公开的普通方法");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 通过Class类的forName方法获得
public static void main(String[] args) throws ClassNotFoundException {
Class c=Class.forName("反射.Person");
System.out.println(c);
}
2、通过类名.class来获得
public static void main(String[] args) {
Class<?> c=Person.class;
}
3、通过类的实例化对象的getClass()方法来获得
public static void main(String[] args) {
Person person=new Person();
Class c=person.getClass();
System.out.println(c);
}
借助Class的newInstance方法可以创建Class类对象所指代的类(Person)的实例化对象
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
//得到Class类的实例化对象,指向了Person这个对象
Class<?> c=Class.forName("反射.Person");
//构建Person类的实例化对象
Person person= (Person) c.newInstance();
//就可以调用Person类的属性了
person.print();
//私有的方法不可以直接访问,如果想要调用私有的属性,需要借助Field类,Method类,Construction类的实例化对象来实现
person.print("张三",10);
}
class类的某一些方法来实例化Field类,Method类,Construction类的实例化对象
Field类
表示类的成员变量/类的属性
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
//得到Class类的实例化对象
Class c= Class.forName("反射.Person");
//创建Filed类,这个Field类的实例化对象指向了name这个变量
Field field= c.getDeclaredField("name");
//创建Person类
Person person=(Person) c.newInstance();
//借助set方法更改person对象的属性(field对象指代的属性)
field.set(person,"zhangsan");
// field.set(person,10); //一定是field对象指代的属性
//借助get方法得到person对象的属性(field对象指代的属性)
String name=(String) field.get(person);
System.out.println(name);
System.out.println(person);
}
如果直接访问私有属性,会报错
需要调用field.setAccessible(true);来设置访问权限,让私有属性可以被访问
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class c = Class.forName("反射.Person");
//指定访问了私有属性
Field field = c.getDeclaredField("age");
field.setAccessible(true);
Person person = new Person();
field.set(person, 10);
int age =(int) field.get(person);
System.out.println(age);
System.out.println(person);
}
Method类
代表类的方法
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class c = Class.forName("反射.Person");
//指定访问了print方法,这个print的方法没有参数
Method method = c.getDeclaredMethod("print");
Person person = new Person();
//传入参数,调用指定的print方法
method.invoke(person);
//调用私有方法
Class c1 = Class.forName("反射.Person");
//指定访问了print方法,这个print的方法参数是String和int
Method method1 = c1.getDeclaredMethod("print",String.class,int.class);
method1.setAccessible(true);
Person person1 = new Person();
//传入参数,调用指定的print方法
method1.invoke(person1,"zhangsan",5);
}
Constructor 类
访问类的构造方法
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class c = Class.forName("反射.Person");
//获取构造方法,构造方法的参数是String
Constructor constructor=c.getDeclaredConstructor(String.class);
//通过构造方法创建Person类的实例
Person person=(Person) constructor.newInstance("zhangsan");
System.out.println(person);
Class c1 = Class.forName("反射.Person");
//获取构造方法,构造方法的参数是String,int
Constructor constructor1=c1.getDeclaredConstructor(String.class,int.class);
constructor1.setAccessible(true);
//通过构造方法创建Person类的实例
Person person1=(Person) constructor1.newInstance("zhangsan",9);
System.out.println(person1);
}
泛型类实现
class Student<K> {
// K[]arr=(K[])new Object[10];//创建泛型数组;这个方式不会报错,但是实际上也不正确
K[]table;
public Student(Class<?> c,int sz){
table=(K[])Array.newInstance(c,10);
}
public void add(K value) {
table[0] = value;
}
public Object get() {
return table[0];
}
}
public class Text {
public static void main(String[] args) throws ClassNotFoundException {
Student<Integer> student = new Student<>(Integer.class,10);
student.add(10);
Object a= student.get();
System.out.println(a);
}
总结
反射可以获得类的任何成员,哪怕是私有的也可以访问,经常用于框架构建
枚举类
枚举类创建
public enum Text {
RED,BLACK,GREEN;
public static void main(String[] args) {
switch (BLACK) {
case RED:
System.out.println("Red");
break;
case BLACK:
System.out.println("BLACK");
break;
case GREEN:
System.out.println("GREEN");
break;
}
}
}
enum表示创建枚举类,Text是这个枚举类的名称
public enum Text { RED,BLACK,GREEN; }
Java 中的每一个枚举都继承自 java.lang.Enum
类。当定义一个枚举类型时,每一个枚举类型成员都可以看作是 Enum 类的实例。这些枚举成员默认都被 final、public, static 修饰,当使用枚举类型成员时,直接使用枚举名称调用成员即可。
每创建一个类都要调用提供的构造方法,构造方法中传入的name是枚举常量的名称,传入的ordinal表示枚举的序号
public enum Text {
RED,BLACK,GREEN;
}
以上等价于
new Enum<Text>(RED,0)
new Enum<Text>(BLACK,1)
new Enum<Text>(GREEN,2)
Enum类的部分方法
1、values方法
public static void main(String[] args) {
//类名.values()调用枚举类的values方法,返回枚举成员构成的数组
//每一个枚举成员都是一个枚举对象,可以使用类名(枚举名称)直接调用
Text[] text = Text.values();
for (Text o:
text ) {
System.out.println(o);
}
}
2、compareTo方法
public static void main(String[] args) {
System.out.println(Text.RED.compareTo(Text.GREEN));
}
3、valueof方法
public static void main(String[] args) {
Text text=Text.valueOf("RED");
System.out.println(text);
}
4、ordinal()
public static void main(String[] args) {
Text text=Text.valueOf("BLACK");
System.out.println(text);
System.out.println(text.ordinal());
}
但是打开Enum类的所有方法,发现并不存在values方法
那么他是怎么来的呢?
新创建一个类
public enum TextEnum {
RED,Green;
}
values方法由编译器自动添加
枚举与反射
不能创建反射类型的实例
所以枚举类型是非常安全的,连反射都不能创建枚举类型