反射
-
类加载器
-
类加载
类加载的描述
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始化这三个步骤来对类进行初始化。如果不出现意外情况,JVM将会连续完成这三个步骤,所以有时也把这三个步骤统称为类加载或者类初始化
类的加载
- 就是指将class文件读入内存,并为之创建一个 java.lang.Class 对象
- 任何类被使用时,系统都会为之建立一个 java.lang.Class 对象类的连接
/*
ClassLoader 中的两个方法
static ClassLoader getSystemClassLoader():返回用于委派的系统类加载器
ClassLoader getParent():返回父类加载器进行委派
*/
public class Test {
public static void main(String[] args) {
//static ClassLoader getSystemClassLoader():返回用于委派的系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader); //AppClassLoader
//ClassLoader getParent():返回父类加载器进行委派
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent); //PlatformClassLoader
ClassLoader c3 = parent.getParent();
System.out.println(c3); //null
}
}
/*
jdk.internal.loader.ClassLoaders$AppClassLoader@78308db1
jdk.internal.loader.ClassLoaders$PlatformClassLoader@2d98a335
null
*/
-
反射
-
反射的概述
是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展
/*
三种方式获取Class对象
1:使用类的class属性来获取该类对应的Class对象。举例:Student.class将会返回Student类对应的Class对象
2:调用对象的getClass()方法,返回该对象所属类对应的Class对象
该方法是Object类中的方法,所有的Java对象都可以调用该方法
3:使用Class类中的静态方法forName(String className),该方法需要传入字符串参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
//使用类的class属性来获取该类对应的Class对象
Class<Student> stuClass = Student.class;
System.out.println(stuClass);
Class<Student> stuClass2 = Student.class;
System.out.println(stuClass == stuClass2);
System.out.println("----------------------");
//调用对象的getClass()方法,返回该对象所属类对应的Class对象
Student stu = new Student();
Class<? extends Student> stuClass3 = stu.getClass();
System.out.println(stuClass == stuClass3);
System.out.println("----------------------");
//使用Class类中的静态方法forName(String className)
Class<?> stuClass4 = Class.forName("com.Reflect.Student");
System.out.println(stuClass == stuClass4);
}
}
/*
class com.Reflect.Student
true
----------------------
true
----------------------
true
*/
-
反射获取构造方法并使用
方法名 |
说明 |
Constructor<?>[] getConstructors() |
返回所有公共构造方法对象的数组 |
Constructor<?>[] getDeclaredConstructors() |
返回所有构造方法对象的数组 |
Constructor getConstructor(Class<?>... parameterTypes) |
返回单个公共构造方法对象 |
Constructor getDeclaredConstructor(Class<?>... parameterTypes) |
返回单个构造方法对象 |
package com.Reflect;
public class Student {
//成员变量:一个私有,一个默认,一个公共
private String name;
int age;
public String address;
//构造方法:一个私有,一个默认,两个公共
public Student() {
}
private Student(String name) {
this.name = name;
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
//成员方法:一个私有,四个公共
private void function() {
System.out.println("function");
}
public void method1() {
System.out.println("method");
}
public void method2(String s) {
System.out.println("method:" + s);
}
public String method3(String s, int i) {
return s + "," + i;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
/*
反射获取构造方法并使用获取对象
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> stuClass = Class.forName("com.Reflect.Student");
//Constructor<?>[] getConstructors() 返回一个包含 Constructor对象的数组, Constructor对象反映了由该 Class对象表示的类的所有公共构造函数
Constructor<?>[] publicConstructors = stuClass.getConstructors(); //公共构造方法数组
for (Constructor<?> stuCon : publicConstructors) System.out.println(stuCon);
System.out.println("------------------");
//Constructor<?>[] getDeclaredConstructors() 返回反映由该 Class对象表示的类声明的所有构造函数的 Constructor对象的数组
Constructor<?>[] allConstructors = stuClass.getDeclaredConstructors(); //所有构造方法数组
for (Constructor<?> stuCon : allConstructors) System.out.println(stuCon);
System.out.println("------------------");
//Constructor提供了一个类的单个构造函数的信息和访问权限 Constructor<?> con = c.getConstructor();
Constructor<?> stuConstructor = stuClass.getConstructor();
//T newInstance(Object... initargs) 使用由此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例
Object student = stuConstructor.newInstance();
System.out.println(student);
}
}
/*
public com.Reflect.Student(java.lang.String,int,java.lang.String)
public com.Reflect.Student()
------------------
public com.Reflect.Student(java.lang.String,int,java.lang.String)
com.Reflect.Student(java.lang.String,int)
private com.Reflect.Student(java.lang.String)
public com.Reflect.Student()
------------------
Student{name='null', age=0, address='null'}
*/
获取构造方法初始化对象
通过反射获取公共的构造方法并创建对象
/*
反射获取构造方法并使用获取对象
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> student = Class.forName("com.Reflect.Student");
//Constructor提供了一个类的单个构造函数的信息和访问权限 Constructor<?> con = c.getConstructor();
//public Student(String name, int age, String address)
Constructor<?> stuConstructor = student.getConstructor(String.class, int.class, String.class);
//T newInstance(Object... initargs) 由Constructor对象表示的构造函数来创建和初始化构造函数的声明类的新实例
Object stu = stuConstructor.newInstance("李茂贞", 25, "岐国");
System.out.println(stu);
}
}
/*
Student{name='李茂贞', age=25, address='岐国'}
*/
/*
暴力反射
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class<?> student = Class.forName("com.Reflect.Student");
//Constructor 提供了一个类的单个构造函数的信息和访问权限 Constructor<?> con = c.getConstructor();
//反射 私有 构造方法private Student(String name)
Constructor<?> stuConstructor = student.getDeclaredConstructor(String.class);
//暴力反射
//将此反射对象的accessible标志设置为指示的布尔值。 值为true表示反射对象应该在使用Java语言访问控制时抑制检查。 值为false表示反射对象应该在使用Java语言访问控制时执行检查,并在类描述中指出变体。
//public void setAccessible(boolean flag):值为true,取消访问检查
stuConstructor.setAccessible(true);
//T newInstance(Object... initargs) 由Constructor对象表示的构造函数来创建和初始化构造函数的声明类的新实例
Object stu = stuConstructor.newInstance("李茂贞");
System.out.println(stu);
}
}
/*
Student{name='李茂贞', age=0, address='null'}
*/
-
Class类获取成员变量对象的方法
方法分类
方法名 |
说明 |
Field[] getFields() |
返回所有公共成员变量对象的数组 |
Field[] getDeclaredFields() |
返回所有成员变量对象的数组 |
Field getField(String name) |
返回单个公共成员变量对象 |
Field getDeclaredField(String name) |
返回单个成员变量对象 |
方法名 |
说明 |
voidset(Object obj,Object value) |
给obj对象的成员变量赋值为value |
/*
反射获取成员变量并使用
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException, NoSuchMethodException {
//获取Class对象
Class<?> student = Class.forName("com.Reflect.Student");
//Field[] getFields() 返回一个包含 Field对象的数组, Field对象反映由该 Class对象表示的类或接口的所有可访问的公共字段
Field[] fields1 = student.getFields();
//Field[] getDeclaredFields() 返回一个 Field对象的数组,反映了由该 Class对象表示的类或接口声明的所有字段
Field[] declaredFields = student.getDeclaredFields();
for (Field fi : declaredFields) System.out.println(fi);
System.out.println("----------------------------");
//Field getField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定公共成员字段
Field address = student.getField("address");
//Field getDeclaredField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定声明字段
Field name = student.getDeclaredField("name");
//获取无参构造方法创建对象
Constructor<?> stuConstructor = student.getConstructor();
//获取Student类对象
Object stu = stuConstructor.newInstance();
//Field提供有关类或接口的单个字段的信息和动态访问
//void set(Object obj, Object value) 将指定的对象参数中由此 Field对象表示的字段设置为指定的新值
address.set(stu, "岐国"); //addressField.set(stu, "岐国"); //给stu的成员变量address赋值为岐国
name.setAccessible(true);
name.set(stu, "李茂贞"); //IllegalAccessException,前面添加 name.setAccessible(true);暴力反射
System.out.println(stu);
}
}
/*
private java.lang.String com.Reflect.Student.name
int com.Reflect.Student.age
public java.lang.String com.Reflect.Student.address
----------------------------
Student{name='李茂贞', age=0, address='岐国'}
*/
/*
反射获取成员变量并使用
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException, NoSuchMethodException {
Class student = Class.forName("com.Reflect.Student");
Constructor<?> stuConstructor = student.getConstructor();
Object stu = stuConstructor.newInstance();
//name = "李茂贞"
Field name = student.getDeclaredField("name");
name.setAccessible(true);
name.set(stu, "李茂贞");
//age = 25
Field age = student.getDeclaredField("age");
age.setAccessible(true);
age.set(stu, 25);
//address = "岐国"
Field address = student.getDeclaredField("address");
address.setAccessible(true);
address.set(stu, "岐国");
System.out.println(stu);
}
}
/*
Student{name='李茂贞', age=25, address='岐国'}
*/
-
反射获取成员变量并使用练习
Class类获取成员方法对象的方法 方法分类
方法名 |
说明 |
Method[] getMethods() |
返回所有公共成员方法对象的数组,包括继承的 |
Method[] getDeclaredMethods() |
返回所有成员方法对象的数组,不包括继承的 |
Method getMethod(String name, Class<?>... parameterTypes) |
返回单个公共成员方法对象 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) |
返回单个成员方法对象 |
/*
反射获取成员方法并使用
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class student = Class.forName("com.Test.Student");
//Method[] getMethods() 返回一个包含 方法对象的数组, 方法对象反映由该 Class对象表示的类或接口的所有公共方法,包括由类或接口声明的对象以及从超类和超级接口继承的类
//获取本类所有父类的公共方法
//Method[] methods1 = student.getMethods();
//Method[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映由 Class对象表示的类或接口的所有声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承方法
Method[] declaredMethods = student.getDeclaredMethods();
for (Method method: declaredMethods) System.out.println(method);
System.out.println("---------------------");
//Method getMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,该对象反映由该 Class对象表示的类或接口的指定公共成员方法
//Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 Class对象
Method dMethod = student.getDeclaredMethod("method1");
//获取无参构造方法创建对象
Constructor stuCon = student.getConstructor();
Object stu = stuCon.newInstance();
//在类或接口上提供有关单一方法的信息和访问权限
//Object invoke(Object obj, Object... args) 在具有指定参数的指定对象上调用此 方法对象表示的基础方法
//Object:返回值类型
//obj:调用方法的对象
//args:方法需要的参数
dMethod.invoke(stu);
}
}
/*
public java.lang.String com.Test.Student.toString()
private void com.Test.Student.function()
public void com.Test.Student.method1()
public java.lang.String com.Test.Student.method3(java.lang.String,int)
public void com.Test.Student.method2(java.lang.String)
---------------------
method
*/
/*
练习:通过反射实现如下操作
Student s = new Student();
s.method1();
s.method2("林青霞");
String ss = s.method3("林青霞",30);
System.out.println(ss);
s.function();
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//获取Class对象
Class student = Class.forName("com.Test.Student");
//Student s = new Student();
Constructor stuCon = student.getConstructor();
Object stu = stuCon.newInstance();
//s.method1();
Method method1 = student.getMethod("method1");
method1.invoke(stu);
//s.method2("林青霞");
Method method2 = student.getMethod("method2", String.class);
method2.invoke(stu, "李茂贞");
// String ss = s.method3("林青霞",30);
// System.out.println(ss);
Method method3 = student.getMethod("method3", String.class, int.class);
Object rensult = method3.invoke(stu, "李茂贞", 25);
System.out.println(rensult);
System.out.println((String)rensult);
//s.function(); //private void function()
// Method m4 = c.getMethod("function"); //NoSuchMethodException: com.itheima_02.Student.function()
Method function = student.getDeclaredMethod("function");
function.setAccessible(true);
function.invoke(stu);
}
}
/*
method
method:李茂贞
李茂贞,25
李茂贞,25
function
*/
-
反射练习之越过泛型检查
/*
练习1:我有一个ArrayList<Integer>集合,现在我想在这个集合中添加一个字符串数据,如何实现?
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//创建集合
ArrayList<Integer> array = new ArrayList<>();
array.add(10);
array.add(50);
array.add(90);
System.out.println(array);
//获取Classd对象
Class<? extends ArrayList> arrayClass = array.getClass();
Method add = arrayClass.getDeclaredMethod("add", Object.class);
add.invoke(array, "hello");
add.invoke(array, "reflect");
System.out.println(array);
}
}
/*
[10, 50, 90]
[10, 50, 90, hello, reflect]
*/
-
运行配置文件中指定类的指定方法
/*
练习2:通过配置文件运行类中的方法
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
/* Teacher tea = new Teacher();
tea.teach();
Student stu = new Student();
//private void study
*/
/*
class.txt
className=xxx
methodName=xxx
*/
//加载数据
FileReader fr = new FileReader("E:\\work_space\\java_work\\java_test\\src\\com\\Test\\conf.txt");
Properties prop = new Properties();
prop.load(fr);
System.out.println(prop);
//通过反射来调用方法
Class obClass = Class.forName(prop.getProperty("className"));
Constructor constructor = obClass.getConstructor();
Object o = constructor.newInstance();
Method method = obClass.getDeclaredMethod(prop.getProperty("methodName"));
method.setAccessible(true);
method.invoke(o);
//通过反射来调用方法
Class obClass2 = Class.forName(prop.getProperty("className2"));
Constructor constructor2 = obClass2.getConstructor();
Object o2 = constructor2.newInstance();
Method method2 = obClass2.getDeclaredMethod(prop.getProperty("methodName2"));
method2.setAccessible(true);
method2.invoke(o2);
}
}
/*
{methodName=teach, methodName2=study, className=com.Test.Teacher, className2=com.Test.Student}
老师教学!
学生学习!
*/
-
模块化
Java语言随着这些年的发展已经成为了一门影响深远的编程语言,无数平台,系统都采用Java语言编写。但是,伴随着发展,Java也越来越庞大,逐渐发展成为一门“臃肿” 的语言。而且,无论是运行一个大型的软件系统,还是运行一个小的程序,即使程序只需要使用Java的部分核心功能, JVM也要加载整个JRE环境。 为了给Java“瘦身”,让Java实现轻量化,Java 9正式的推出了模块化系统。Java被拆分为N多个模块,并允许Java程序可以根据需要选择加载程序必须的Java模块,这样就可以让Java以轻量化的方式来运行
其实,Java 7的时候已经提出了模块化的概念,但由于其过于复杂,Java 7,Java 8都一直未能真正推出,直到Java 9才真正成熟起来。对于Java语言来说,模块化系统是一次真正的自我革新,这种革新使得“古老而庞大”的Java语言重新焕发年轻的活力
package com.toroidal01;
public class Studnet {
public void study(){
System.out.println("学生学习!");
}
}
module myOne {
exports com.toroidal01;
}
module myTow {
requires myOne;
}
package com.toroidal;
import com.toroidal01.Studnet;
public class Test {
public static void main(String[] args) {
Studnet stu = new Studnet();
stu.study();
}
}
-
模块服务的基本使用