多线程知识点目录
多线程并发(1)- https://www.jianshu.com/p/8fcfcac74033
多线程并发(2)-https://www.jianshu.com/p/a0c5095ad103
多线程并发(3)-https://www.jianshu.com/p/c5c3bbd42c35
多线程并发(4)-https://www.jianshu.com/p/e45807a9853e
多线程并发(5)-https://www.jianshu.com/p/5217588d82ba
多线程并发(6)-https://www.jianshu.com/p/d7c888a9c03c
一、动态语言
动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化。比如常见的JavaScript
就是动态语言,除此之外Ryby
、Python
等也属于动态语言,而C、C++则不属于动态语言。从反射角度说Java属于半动态语言。
二、反射机制概念
Java反射机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。
三、反射的应用场合
3.1 编译时类型和运行时类型
在Java程序中许多对象在运行时会出现两种类型:编译时类型和运行时类型。
编译时类型(Compile-time Type)通常是你声明变量时所使用的类型。这个类型在编译时期确定,并且会用于编译期的检查,比如类型检查和转换。
运行时类型(Runtime Type)是对象实际的生命周期中的具体类型。这个类型在运行时确定,并且可以动态地改变。
例如:
Person p = new Student
在这里,p
的编译时类型是Person
,这是你在声明变量时指定的类型。然而,p
的运行时类型实际上是Student
,因为p
实际上指向的是一个Student
类型的对象。
3.2 编译时类型无法获取具体方法
编译时类型无法获取具体方法的原因是Java的类型擦除机制。在Java中,泛型类型的信息是在编译期确定的,但这些信息在运行时会被擦除,以便支持Java的动态类型安全和性能优化。
因此,尽管你可以在编译时获取变量的类型信息,但是在运行时,Java虚拟机(JVM)会忽略这些类型信息,而只关注对象的实际运行时类型。这意味着在运行时,你无法通过编译时类型来获取具体方法,因为编译时类型的信息在运行时被擦除了。
如果你想在运行时获取具体方法的信息,你可以使用Java的反射API。反射API允许你在运行时检查类、接口、字段和方法的信息,甚至可以调用对象的方法。通过反射API,你可以动态地获取对象的运行时类型信息,并据此进行相应的操作。
四、Java反射API
Java反射API是一组在Java编程语言中用于在运行时检查和操作类、接口、字段和方法的功能强大的API。通过反射API,你可以在运行时获取类的信息,创建对象,调用方法,获取和设置字段值等。
以下是一些常用的反射API:
- Class类:反射的核心类,代表一个类或接口,提供了一系列方法用于获取类的信息,如名称、注解、成员变量和方法等。
- Field类:代表一个字段,提供了一系列方法用于获取字段的类型、名称、访问修饰符等信息,并可以获取和设置字段的值。
- Method类:代表一个方法,提供了一系列方法用于获取方法的参数、返回值、访问修饰符等信息,并可以调用该方法。
- Constructor类:代表一个构造方法,提供了一系列方法用于创建对象实例。
五、反射使用步骤
获取想要操作的Class对象,这是反射的核心,可以通过Class对象任意调用类的方法。
调用Class类的方法是反射的使用阶段。
-
使用反射API来操作这些信息。
import java.lang.reflect.Method; public class ReflectionExample { public static void main(String[] args) { try { // 获取String类的Class对象 Class<?> stringClass = String.class; // 获取一个构造方法 Constructor<?> stringConstructor = stringClass.getConstructor(String.class); // 创建新的String对象 Object stringObject = stringConstructor.newInstance("Hello World"); // 获取并调用String类的length()方法 Method lengthMethod = stringClass.getMethod("length"); int length = (Integer) lengthMethod.invoke(stringObject); System.out.println("Length: " + length); } catch (Exception e) { e.printStackTrace(); } } }
六、获取Class对象的3种方法
6.1 调用某个对象的getClass方法
Person p = new Persion();
Class clazz = p.getClass();
6.2 调用某个类的class属性来获取该类对应的Class对象
Class clazz = p.class;
6.3 使用class类中的forName()静态方法(最安全、性能最好)
Class clazz = Class.forName("com.example.MyClass");
注意:使用forName()方法时,需要确保类的完全限定名是正确的,否则会抛出ClassNotFoundException异常。
6.4 通过Class对象获取类中方法和属性
// 获取Person类的Class对象
Class clazz = Class.forName("com.example.Person");
// 获取Person类的所有方法信息
Method[] methodArr = clazz.getDeclaredMethods();
for(Method m : methodArr){
System.out.println(m.toString());
}
// 获取Person类的所有成员属性
Field[] fieldArr = clazz.getDeclaredFields();
for(Field f : fieldArr){
System.out.println(f.toString());
}
// 获取Person类的所有构造方法信息
Constructor[] constructorArr = clazz.getDeclaredConstructors();
for(Constructor c : constructorArr){
System.out.println(c.toString());
}
七、创建对象的两种方法
7.1 Class对象的newInstance()
使用Class对象的newInstance()方法来创建该Class对象对应类的实例,但是,这种方法要求该Class对象对应的类由默认的空构造器。
Class clazz = Class.forName("com.example.Person");
Person p = (Person) clazz.newInstance();
7.2 调用Constructor对象的newInstance()
先试用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建Class对象对应类的实例,通过这种方法可以选定构造方法创建实例。
Class clazz = Class.forName("com.example.Person");
// 获取构造方法并创建对象
Constructor c = clazz.getDeclaredConstructor(String.class,String.class,int class);
// 创建对象并设置属性
Person p = (Person) c.newInstance("王梅梅","女",18);