Featured image of post Java反射

Java反射

Java安全之反射

1.Java反射专题

反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对像的属性及方法。反射在设计模式和框架底层都会用到。反射面前一切都是纸老虎

1.1.反射是什么—一个需求引出反射

1
2
3
根据配置文件re.properties内容创建Cat对象并调用hi方法
classfullpath=com.edu.Cat
method=hi

开闭原则(ocp原则):不修改源码,来扩展功能

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Question {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //根据配置文件re.properties内容,创建Cat对象并调用hi方法
        //使用之前学的无法解决,只能使用反射进行解决
        //使用Properties类读取配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classfullpath = properties.get("classfullpath").toString();
        String methodName = properties.get("method").toString();
        System.out.println(classfullpath);
        System.out.println(methodName);


        //1.加载类,返回class类型的对象cls
        Class cls = Class.forName(classfullpath);
        //2.通过cls得到你加载类的对象示例
        Object object = cls.newInstance();
        System.out.println("object对象的运行类型"+object.getClass());   //运行类型
        //3.通过cls得到你加载的类com.edu.Cat的methodName "hi"对象
        //即:在反射中,可以把方法视为对象,万物皆对象
        Method method1 = cls.getMethod(methodName);
        //通过method1调用方法invode
        method1.invoke(object);       
    }
}

1.2.反射原理图

这张图片展示了Java程序的三个主要阶段:代码阶段/编译阶段、Class类阶段(加载阶段)和Runtime运行阶段。

1
2
3
在这个阶段开发者编写Java源代码文件例如Cat.java
代码中定义了类Cat包括私有字符串变量name公共构造函数Cat()和公共方法hi()
通过Java编译器源代码被编译成字节码文件Cat.class
1
2
3
在这个阶段类加载器ClassLoader将字节码文件Cat.class加载到内存中
加载后形成了Class对象包含了类的元数据如成员变量Field)、构造器Constructor和成员方法Method)。
这些元数据存储在堆内存中供后续的运行时使用
1
2
3
4
5
6
在运行时阶段Java虚拟机JVM执行字节码
通过new Cat()创建Cat类的实例对象cat
该对象知道它属于哪个Class对象并且可以通过该Class对象访问其元数据
得到Class对象后可以进行以下操作
创建对象调用构造函数
操作对象的属性和方法

1.3.反射机制

1.3.1.java.lang.reflect.Field—获取某个类的字段

** java.lang.reflect.Field:代表类的成员变量,Field类表示某个类的成员变量**

获取某个类的字段

getField不能获取private修饰的私有属性

getDeclaredField可用来获取私有属性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.edu.reflection;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Reflection1 {

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //使用Properties类读取配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classfullpath = properties.get("classfullpath").toString();
        String methodName = properties.get("method").toString();

        //1.加载类,返回class类型的对象cls
        Class cls = Class.forName(classfullpath);
        //2.通过cls得到你加载类的对象示例
        Object object = cls.newInstance();
        System.out.println("object对象的运行类型"+object.getClass());   //运行类型
        //3.通过cls得到你加载的类com.edu.Cat的methodName "hi"对象
        //即:在反射中,可以把方法视为对象,万物皆对象
        Method method1 = cls.getMethod(methodName);
        //通过method1调用方法invode
        method1.invoke(object);

        //java.lang.reflect.Field:代表类的成员变量,Field类表示某个类的成员变量
        //获取某个类的字段
        // getField不能获取私有的属性
        Field name = cls.getField("age");
        System.out.println(name.get(object));    //10
        //getDeclaredField可用来获取私有属性
        Field name1 = cls.getDeclaredField("name");
        name1.setAccessible(true);
        System.out.println(name1.get(object));
    }
}

1.3.2.java.lang.reflect.Constructor:获取构造器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
java.lang.reflect.Constructor代表类的构造方法Constructor表示构造器


//1.加载类,返回class类型的对象cls
Class cls = Class.forName(classfullpath);
//2.通过cls得到你加载类的对象示例
Object object = cls.newInstance();
System.out.println("object对象的运行类型"+object.getClass());   //运行类型
//3.通过cls得到你加载的类com.edu.Cat的methodName "hi"对象
//即:在反射中,可以把方法视为对象,万物皆对象
Method method1 = cls.getMethod(methodName);
//通过method1调用方法invode
method1.invoke(object);

//java.lang.reflect.Constructor:代表类的构造方法,Constructor表示构造器
//获取无参构造器
Constructor constructor = cls.getConstructor();
System.out.println(constructor);
//获取有参构造器
Constructor constructor1 = cls.getConstructor(String.class);    //这里的String.class就是String类的Class对象
System.out.println(constructor1);

1.4.反射的优点与缺点

优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。

缺点:使用反射是基于解释执行,对执行速度有影响

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class Reflection2 {
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {
        m1();
        m2();
        m3();
    }
    //使用传统方法创建Cat对象耗时
    public static void m1(){
        long start = System.currentTimeMillis();
        for (int i = 0;i<1000000;i++){
            Cat cat = new Cat();
        }
        long end = System.currentTimeMillis();
        System.out.println("传统方法耗时:"+(end-start));
    }

    public static void m2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        long start = System.currentTimeMillis();
        Class<?> cls = Class.forName("com.edu.Cat");
        Object o = cls.newInstance();
        Method hi = cls.getMethod("hi");
        for (int i = 0;i<1000000;i++){
            hi.invoke(o);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射方法耗时:"+(end-start));
    }

    public static void m3() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        long start = System.currentTimeMillis();
        Class<?> cls = Class.forName("com.edu.Cat");
        Object o = cls.newInstance();
        Method hi = cls.getMethod("hi");
        hi.setAccessible(true);
        for (int i = 0;i<1000000;i++){
            hi.invoke(o);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射方法耗时:"+(end-start));
    }
}

1.5.通过反射获取类的结构信息

//getName:获取全类名

//getSimpleName:获取简单类名

//getFields:获取所有public修饰的属性,包括本类以及父类的

//getDeclaredFields:获取本类中所有属性

//getMethods:获取所有public修饰的方法,包含本类以及父类

//getDeclaredMethods:获取本类中所有方法

//getConstructors:获取public修饰的构造器,只包含本类不包含父类

//getDeclaredConstructors:获取本类中所有构造器

//getPackage:以package形式返回包信息

//getSuperclass:以class形式返回父类信息

//getInterfaces:以Class形式返回接口信息

//getAnnotations:以Annotation[]形式返回注解信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package com.edu.reflection;

import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/*
* 演示如何通过反射获取类的结构信息
* */
public class ReflectionUtils {
    public static void main(String[] args) {
    }

    //第一组方法API
    @Test
    public void api01() throws ClassNotFoundException {
        //得到class对象
        Class<?> cls = Class.forName("com.edu.reflection.Person");
        //getName:获取全类名
        System.out.println(cls.getName());  //com.edu.reflection.Person
        //getSimpleName:获取简单类名
        System.out.println(cls.getSimpleName());//Person
        //getFields:获取所有public修饰的属性,包括本类以及父类的
        Field[] fields = cls.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());  //hobby,name
        }
        //getDeclaredFields:获取本类中所有属性
        Field[] declaredFields = cls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName()); //name,age,job,sal
        }
        //getMethods:获取所有public修饰的方法,包含本类以及父类
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }
        //getDeclaredMethods:获取本类中所有方法
        Method[] declaredMethods = cls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod.getName());
        }
        //getConstructors:获取public修饰的构造器,只包含本类
        Constructor<?>[] constructors = cls.getConstructors();
        //getDeclaredConstructors:获取本类中所有构造器
        Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();
        //getPackage:以package形式返回包信息
        System.out.println(cls.getPackage());  //com.edu.reflection
        //getSuperclass:以class形式返回父类信息
        Class<?> superclass = cls.getSuperclass();
        System.out.println(superclass);      //com.edu.reflection.A
        //getInterfaces:以Class形式返回接口信息
        Class<?>[] interfaces = cls.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println(anInterface.getName());
        }
        //getAnnotations:以Annotation[]形式返回注解信息
        Annotation[] annotations = cls.getAnnotations();
        System.out.println(annotations); //Deprecated

    }
}

class A{
    public String hobby;
    public void hi(){}
}
interface IA{

}
interface IB{

}

@Deprecated
class Person extends A implements IA,IB{
    //四种不同访问权限的属性
    public String name;
    protected int age;
    String job;
    private double sal;

    public void m1(){}
    protected void m2(){}
    void m3(){}
    private void m4(){}
}

//getModifiers:以int形式返回修饰符,默认修饰符是0,public是1,private是2,protected是4,static是8,final是16

如果有属性是punlic(1) static(8) = 9 修饰,那么他的结果是相加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    public void api02() throws ClassNotFoundException{
        //得到class对象
        Class<?> cls = Class.forName("com.edu.reflection.Person");
        //getDeclaredFields:获取本类中所有属性
        Field[] declaredFields = cls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName()); //name,age,job,sal
            System.out.println("该属性的修饰符值="+declaredField.getModifiers());
            System.out.println("该属性对应的类型"+declaredField.getType()); //class java.lang.String
        }
        //getDeclaredMethods:获取本类中所有方法
        Method[] declaredMethods = cls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类中所有方法:"+declaredMethod.getName());
            System.out.println("本类中方法所对应修饰符的值"+declaredMethod.getModifiers());
            System.out.println("该方法返回类型"+declaredMethod.getReturnType()); //void
            //输出当前这个方法的形参数组情况
            Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println("该方法的形参类型"+parameterType);
            }
        }
    }

1.6.通过反射爆破创建对象实例

方法1:调用类中的public修饰的无参构造器

方法2:调用类中的指定构造器

Class类相关方法:

1
2
3
newInstance调用类中的无参构造器获取对应类的对象
getConstructor(Class...clazz)根据参数列表获取对应的public构造器对象
getDecalaredConstructor(Class...clazz):根据参数列表获取对应的所有构造器对象

Constructor类相关方法:

1
2
setAccessible爆破
newInstance(Object...obj):调用构造器
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.edu;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/*
* 演示通过反射机制创建实例
* */
public class CreateInstance {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //1.先获取User类的Class对象
        Class<?> Userclass = Class.forName("com.edu.User");
        //2.通过public的无参构造器创建实例
        Object o = Userclass.newInstance();
        System.out.println(o);    //姓名为张三*******年龄为13
        //3.通过public的有参构造器创建实例
        //此时此刻,这个constructor对象就是下面这个构造器
        /*
        *     public User(String name){  //public有参构造器
                this.name = name;
        */
        //3.1.先得到对应的构造器,getConstructor返回public的构造器
        Constructor<?> constructor = Userclass.getConstructor(String.class);
        //3.2.创建实例,并传入实参
        Object lisi = constructor.newInstance("lisi");
        System.out.println(lisi);   //姓名为lisi*******年龄为13

        //4.通过非public的有参构造器创建实例---私有
        Constructor<?> declaredConstructor = Userclass.getDeclaredConstructor(int.class, String.class);
        declaredConstructor.setAccessible(true);  //爆破,使用反射可以访问私有的private构造器
        Object o1 = declaredConstructor.newInstance(18,"wangwu");
        System.out.println(o1);
    }

}

class User{
    private int age = 13;
    private String name = "张三";
    public User(){}      //无参 public
    public User(String name){  //public有参构造器
        this.name = name;
    }
    private User(int age,String name){  //有参 私有
        this.age = age;
        this.name = name;
    }
    @Override
    public String toString() {
        return "姓名为"+name+"*******年龄为"+age;
    }
}

1.7.通过反射爆破操作属性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.edu;

import java.lang.reflect.Field;

/*
* 演示反射访问操作属性
* */
public class ReflectAccess {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        //1.得到Student类对应的class对象
        Class<?> StuClass = Class.forName("com.edu.Student");
        //2.创建一个对象
        Object o = StuClass.newInstance(); //o的运行类型为Student
        //3.使用反射得到age属性对象
        Field age = StuClass.getField("age");
        //通过反射操作age属性
        age.set(o,18);
        //反射操作name属性,name属性私有且静态
        Field name = StuClass.getDeclaredField("name");
        //对name进行爆破
        name.setAccessible(true);
        //name.set(o,"张三");
        name.set(null,"张三");  //因为name有static属性,所以o也可以写成null
        System.out.println(o);
    }
}
class Student{
    public int age;
    private static String name;

    public Student(){

    }
    @Override
    public String toString() {
        return "Student{" +
                "age=" + age + "......." +
                "name" + name +
                '}';
    }
}

1.8.通过反射爆破操作方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.edu;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/*
* 演示反射调用方法
* */
public class ReflectAccessMethod {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //1.得到Boss类对应的class对象
        Class<?> cls = Class.forName("com.edu.Boss");
        //2.创建对象
        Object o = cls.newInstance();
        //3.得到hi方法对象
        Method hi = cls.getMethod("hi",String.class);
        //4.调用方法
        Object invoke = hi.invoke(o,"666");
        Method say = cls.getDeclaredMethod("say", int.class, String.class, char.class);
        say.setAccessible(true);
        Object invoke1 = say.invoke(o, 100, "张三", '男');
        System.out.println(invoke1);
        //因为say方法是静态的,所以对象位置可以使用null代替
        System.out.println(say.invoke(null, 99, "小红", '女'));
        //5.在反射中,如果方法有返回值,统一返回object
    }

}

class Boss{
    public int age;
    private static String name;

    public Boss(){}

    private static String say(int n,String s,char c){
        return n + "" + s + "" + c;
    }
    public void hi(String s){
        System.out.println("hi"+s);
    }
}

1.9.小练习

利用反射和File完成以下功能

1.利用Class类的forName方法得到File类的class对象

2.在控制台打印File类的所有构造器

3.通过newInstance的方法创建File对象,并创建mynew.txt文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.edu.homework;


import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/*
* */
public class homework2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.利用Class类的forName方法得到File类的class对象
        Class<?> cls = Class.forName("java.io.File");
        //2.得到所有构造器
        Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println("File的构造器"+declaredConstructor);
        }
        //3.通过指定构造器创建文件file对象
        Constructor<?> declaredConstructor = cls.getDeclaredConstructor(String.class);
        String filepath = "E:\\mynew.txt";
        Object fileobject = declaredConstructor.newInstance(filepath);  //创建file对象,运行类型就是File
        //4.得到createNewFile的方法对象
        Method createNewFile = cls.getMethod("createNewFile");
        createNewFile.invoke(fileobject);  //创建文件,调用createNewFile
        //
        System.out.println(fileobject.getClass());
        System.out.println("创建文件成功:"+filepath);
        
    }
}

2.Class类

1
2
3
4
5
6
7
8
1.Class也是类因此也继承object类[类图]
2.Class类对象不是new出来的而是系统创建的
3.对于某个类的Class类对象在内存中只有一份因为类只加载一次
4.每个类的实例都会记得自己是由哪个Class实例所生成
5.通过Class可以完整地得到一个类的完整结构,通过一系列API
6.Class对象是存放在堆的
7.类的字节码二进制数据是放在方法区的有的地方称为类的元数据包括方法代码
变量名方法名访问权限等等) 

https://www.zhihu.com/question/38496907

1
2
3
4
5
        //3.对于某个类的Class类对象,在内存中只有一份,因为类只加载一次
        Class<?> cls1 = Class.forName("com.edu.Cat");
        Class<?> cls2 = Class.forName("com.edu.Cat");
        System.out.println(cls1.hashCode());
        System.out.println(cls2.hashCode());

2.1.Class类常用方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.edu.Class;

import com.edu.Car;

import java.lang.reflect.Field;

public class class2 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        String classPath = "com.edu.Car";
        //1.获取Car类对应的Class对象
        //<?>表示不确定的Java类型
        Class<?> cls = Class.forName(classPath);
        System.out.println(cls);  //显示cls对象,是哪个类的Class对象 com.edu.Car
        System.out.println(cls.getClass());   //输出cls的运行类型 java.lang.Class

        //2.得到包名 ---- getPackage().getName()
        System.out.println(cls.getPackage().getName());    //com.edu
        //3.得到全类名 ----- getName()
        System.out.println(cls.getName());    //com.edu.Car
        //4.通过cls创建对象实例 ----newInstance()
        Car car = (Car)cls.newInstance();
        System.out.println(car);          //Car{brand='宝马', price=19999999, color='红色'}
        //5.通过反射获取属性 ---getField
        Field field = cls.getField("brand");
        System.out.println(field.get(car));      //宝马
        //6.通过反射修改属性 -------field.set(car,"奔驰");
        field.set(car,"奔驰");
        System.out.println(field.get(car));      //奔驰

        //7.我希望获取到所有属性 --------cls.getFields()
        Field[] fields = cls.getFields();
        for (Field field1 : fields) {
            System.out.println(field1.getName());   //brand  price  color
        }
    }
}

2.2.获取Class对象的六种方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*
* 获取class对象的各种方式
* */
public class GetClass {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.已知一个类的全类名,且在类的类路径下,可通过Class的静态方法forname()获取
        //应用场景:多用于配置文件,读取全路径加载类
        Class<?> cls1 = Class.forName("com.edu.Car");
        System.out.println(cls1);

        //2.若知道具体类,通过类的class获取,该方式是最安全可靠,程序性能最高实例
        //应用场景:多用于参数传递,比如通过反射得到对应构造器对象
        Class<Car> cls2 = Car.class;
        System.out.println(cls2);

        //3.已知某个类的实例,调用该实例的getClass()方法获取Class对象
        //应用场景:通过创建好的对象,获取Class对象
        Car car = new Car();
        Class<? extends Car> cls3 = car.getClass();
        System.out.println(cls3);

        //4.通过类加载器【有4种类加载器】获取到类的Class对象
        //(1)先获取类加载器 Car
        ClassLoader classLoader = car.getClass().getClassLoader();
        //(2)通过类加载器得到class对象
        Class<?> cls4 = classLoader.loadClass("com.edu.Car");
        System.out.println(cls4);

        //cls1 cls2 cls3 cls4其实是同一个对象
        System.out.println(cls1.hashCode());
        System.out.println(cls2.hashCode());
        System.out.println(cls3.hashCode());
        System.out.println(cls4.hashCode());

        //5.基本数据类型(int,char,boolean,float,double,byte,long,short)
        //获取Class对象
        Class cls5 = long.class;
        System.out.println(cls5);

        //6.基本数据类型对应的包装类,可通过.type得到Class类对象
        Class cls6 = Integer.TYPE;
        System.out.println(cls6);
        
    }
}

2.3.哪些类型有Class对象

1.外部类,成员内部类,静态内部类,局部内部类,匿名内部类

2.interface 接口

3.数组

4.enum 枚举类型

5.annotation:注解

6.基本数据类型

7.Void

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package com.edu.Class;

import java.io.Serializable;

public class AlltypeClass {
    public static void main(String[] args) {
        Class<String> cls1 = String.class; //外部类
        Class<Serializable> cls2 = Serializable.class; //接口
        Class<Integer[]> cls3 = Integer[].class; //数组
        Class<float[][]> cls4 = float[][].class; //二维数组
        Class<Deprecated> cls5 = Deprecated.class; //注解
        Class<Thread.State> cls6 = Thread.State.class; //枚举
        Class<Long> cls7 = long.class; //基本数据类型
        Class<Void> cls8 = void.class; //void类型
        Class<Class> cls9 = Class.class; //
    }
}

3.类加载

3.1.动态加载与静态加载

静态加载:编译时加载相关类,如果没用则报错,依赖性太强

动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Classload1 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入key");
        String key = sc.next();
        switch (key){
            case "1" :
                Dog dog = new Dog();       //静态加载,编译时直接报错,依赖性强
                dog.cry();
                break;
            case "2":
                //反射--->动态加载
                Class<?> cls = Class.forName("Dog");  //动态加载,编译时可通过,运行时没用该类才会报错
                Object o = cls.newInstance();
                Method method = cls.getMethod("h1");
                method.invoke(o);
                break;
            default:
                System.out.println("do nothing....");
        }
    }
}

3.2.类加载流程图

类加载每个阶段需要干的事

3.3.类加载5个阶段

3.3.1.加载阶段

JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象

3.3.2.连接阶段

验证阶段

目的是确保当前Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全

包括:文件格式验证(是否以魔数 0xcafebabe开头),元数据验证,字节码验证和符号引用验证

可以考虑使用-X verify:none参数来关闭大部分类验证措施,缩短虚拟机类加载的时间

准备阶段

1
2
3
4
5
6
7
8
class A{
    //1.n1是实例变量,不是静态变量,因此在准备阶段,是不会分配内存的
    //2.n2是静态变量,准备阶段需要分配内存,n2的默认值为0,而不是20,20是在初始化阶段进行赋值的
    //3.n3是常量,他和静态变量不一样,因为一旦赋值就不变,n3 = 30
    public int n1 = 10;
    public static int n2 = 20;
    public static final int n3 = 30;
}

解析阶段

虚拟机将常量池内的符号引用替换为直接引用的过程

3.3.3.初始化阶段

到初始化阶段才真正开始执行类中定义的Java程序代码,此阶段是执行()方法的过程。

()方法由编译器**按语句在源文件中出现的顺序,依次收集类中所有静态变量的赋值动作和静态代码块中**的语句,并进行合并

虚拟机会保证一个类的()方法在多线程环境中被正确的加锁,同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.edu.ClassLoad;

/*
* 类加载初始化阶段
* */
public class ClassLoad3 {
    public static void main(String[] args) {
        //1.加载B类,并生成 B的class对象
        //2.连接 num = 0;
        //3.初始化阶段:依次收集类中所有静态变量的赋值动作和静态代码块中的语句,并合并
        //client(){
        //          static {
        //        System.out.println("B 的静态代码块被执行");
        //        num = 300;
        //        num = 100;
        //        }
                //合并之后num=100
        // }
        //new B();
        System.out.println(B.num);
    }
}
class B{
    static {
        System.out.println("B 的静态代码块被执行");
        num = 300;
    }

    static int num = 100;

    public B(){   //构造器不会执行,除非你new 了B这个对象才会执行
        System.out.println("B 的构造器被执行");
    }
}
By Lsec
最后更新于 Jun 09, 2025 12:52 +0800
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计
¹鵵ҳ