JavaSE——08反射机制

目录

08 反射机制

1、关于反射机制

1.1 反射机制有什么用?

1.2 反射机制的相关类在哪个包下?

1.3 反射机制相关的重要的类有哪些?

1.4 在java中获取Class的三种方式

1.5 获取了Class之后,可以调用无参数构造方法来实例化对象

1.6、如果你只想让一个类的“静态代码块”执行的话,你可以怎么做?

1.7 关于路径问题

1.8 IO流方式读取配置文件

1.9 直接以流的形式返回:

1.10 IO + Properties快速绑定属性资源文件

2、关于JDK中自带的类加载器:

2.1 什么是类加载器?

2.2 JDK中自带了3个类加载器

2.3 关于三个类加载器

2.4 java中为了保证类加载的安全,使用了双亲委派机制。

3、Field

3.1 通过反射机制获取属性的常用方法

3.2 通过反射机制反编译一个类的属性

3.3 通过反射机制访问一个java对象的属性(重点)

4、可变长度参数

5、Method

5.1 通过反射机制获取类的Method的常用方法、

5.2 通过反射机制访问一个java对象的属性(重点)

6、Construct

6.1 Construct常用的方法

6.2 通过反射机制new对象

7、获取类的父类和接口


08 反射机制

1、关于反射机制

1.1 反射机制有什么用?

​ 通过java语言中的反射机制可以操作字节码文件。
​ 优点类似于黑客。(可以读和修改字节码文件。)
​ 通过反射机制可以操作代码片段。(class文件。)

反射机制使得对象的创建更加地灵活,可以通过读取配置文件的方式随意改变new的对象,不会将java代码写死

1.2 反射机制的相关类在哪个包下?

java.lang.reflect.*;

1.3 反射机制相关的重要的类有哪些?

​ java.lang.Class:代表整个字节码,代表一个类型,代表整个类。

​ java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。

​ java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法

​ java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。

java.lang.Class:
    public class User{
        // Field
        int no;

        // Constructor
        public User(){

        }
        public User(int no){
            this.no = no;
        }

        // Method
        public void setNo(int no){
            this.no = no;
        }
        public int getNo(){
            return no;
        }
    }

1.4 在java中获取Class的三种方式

​ 第一种:

Class c = Class.forName("完整类名");
//这个完整的类名可以通过读取配置文件的方式获取

​ 第二种:

Class c = 对象.getClass();

​ 第三种:

Class c = int.class;
Class c = String.class;

1.5 获取了Class之后,可以调用无参数构造方法来实例化对象

​ //c代表的就是日期Date类型
​ Class c = Class.forName(“java.util.Date”);

​ //实例化一个Date日期类型的对象
​ Object obj = c.newInstance();

​ 一定要注意:
​ newInstance()底层调用的是该类型的无参数构造方法。
​ 如果没有这个无参数构造方法会出现"实例化"异常。

1.6、如果你只想让一个类的“静态代码块”执行的话,你可以怎么做?

​ Class.forName(“该类的类名”);
​ 这样类就加载,类加载的时候,静态代码块执行!!!!
​ 在这里,对该方法的返回值不感兴趣,主要是为了使用“类加载”这个动作。

1.7 关于路径问题

String path = Thread.currentThread().getContextClassLoader()
					 .getResource("写相对路径,但是这个相对路径从src出发开始找").getPath();	

String path = Thread.currentThread().getContextClassLoader()
					.getResource("abc").getPath();	//必须保证src下有abc文件。

String path = Thread.currentThread().getContextClassLoader()
					.getResource("a/db").getPath();	//必须保证src下有a目录,a目录下有db文件。
	
String path = Thread.currentThread().getContextClassLoader()
					 .getResource("com/bjpowernode/test.properties").getPath();	
	//必须保证src下有com目录,com目录下有bjpowernode目录。
	//bjpowernode目录下有test.properties文件。

​ 这种方式是为了获取一个文件的绝对路径。(通用方式,不会受到环境移植的影响。),但是该文件要求放在类路径下,换句话说:也就是放到src下面。

​ src下是类的根路径。

1.8 IO流方式读取配置文件

//获取一个文件的绝对路径
String path = Thread.currrntThread().getContextClassLoader()
    								.getResource("classinfo2.properties").getPath();
FileReader reader = new FileReader(path);
Properties pro = new Properties();
pro.load(reader);
reader.close();
//通过key获取value
String class Name = pro.getProperty("className");
//这里就得到了配置文件中的Name信息,从而可以使用反射机制来new对象
System.out.println(className);

1.9 直接以流的形式返回:

InputStream reader = Thread.currentThread().getContextClassLoader()
							.getResourceAsStream("com/bjpowernode/test.properties");
Properties pro = new Properties();
pro.load(reader);
reader.close();
//通过key获取value
String class Name = pro.getProperty("className");
System.out.println(className);

1.10 IO + Properties快速绑定属性资源文件

​ //要求:第一这个文件必须在类路径下
​ //第二这个文件必须是以.properties结尾。

ResourceBundle bundle = ResourceBundle.getBundle("com/bjpowernode/test");
String value = bundle.getString(key);

2、关于JDK中自带的类加载器:

2.1 什么是类加载器?

​ 专门负责加载类的命令/工具。ClassLoader

2.2 JDK中自带了3个类加载器

​ 启动类加载器:rt.jar
​ 扩展类加载器:ext/*.jar
​ 应用类加载器:classpath

2.3 关于三个类加载器

假设有这样一段代码:

	String s = "abc";

代码在开始执行之前,会将所需要类全部加载到JVM当中。
通过类加载器加载,看到以上代码类加载器会找String.class文件,找到就加载,那么是怎么进行加载的呢?

  • 首先通过“启动类加载器”加载。
    注意:启动类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jar。
    rt.jar中都是JDK最核心的类库。
  • 如果通过“启动类加载器”加载不到的时候,会通过"扩展类加载器"加载。
    注意:扩展类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext*.jar
  • 如果“扩展类加载器”没有加载到,那么会通过“应用类加载器”加载。
    注意:应用类加载器专门加载:classpath中的类。

2.4 java中为了保证类加载的安全,使用了双亲委派机制。

​ 优先从启动类加载器中加载,这个称为“父”。“父”无法加载到,再从扩展类加载器中加载,这个称为“母”。双亲委派。如果都加载不到,才会考虑从应用类加载器中加载。直到加载到为止。

3、Field

3.1 通过反射机制获取属性的常用方法

获取到所有public修饰的属性

Field[] fields = 类名.getFields();

获取到属性名

String fieldName = fields[1].getName();//com.bjpowernode.java.bean.Stu
String fieldName = fields[1].getSimpleName();//Stu

获取所有的属性

Field[] fields = 类名.getDeclaredFields();

获取属性的类型

Class fieldType = fields[1].getType();
String fName = fieldType.getName();

获取属性的修饰符列表

int i = fields[1].getModifiers();//返回的是修饰符的代号
String modifierString = Modifier.toString(i);

3.2 通过反射机制反编译一个类的属性

package reflect;
//通过反射机制反编译一个类的属性
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class reflextTest07 {
    public static void main(String[] args) throws ClassNotFoundException {
        StringBuilder stringBuilder = new StringBuilder();//为了拼接字符串

        Class studentClass = Class.forName("reflect.Student");
        Field[] fields = studentClass.getDeclaredFields();

        stringBuilder.append(Modifier.toString(studentClass.getModifiers()) + " class " + studentClass.getSimpleName() + "{" + "\n");
        for(Field field:fields){
            stringBuilder.append("\t");
            stringBuilder.append(Modifier.toString(field.getModifiers()) + " ");
            stringBuilder.append(field.getType() + " ");
            stringBuilder.append(field.getName());
            stringBuilder.append(";" + "\n");
        }


        stringBuilder.append("}");
        System.out.println(stringBuilder);
    }
}

3.3 通过反射机制访问一个java对象的属性(重点)

给属性赋值set、获取属性的值get

三要素:给s对象的no属性赋值1111
要素1:对象5
要素2:no属性
要素3:1111

我们不使用反射机制,怎么去访问一个对象的属性呢?

//创建对象
Student s = new Student();

//给属性赋值
s.no = 1111;

//读属性值
System.out.println(s.no);

使用反射机制,怎么去访问一个对象的属性。(set get)

//获取类,通过类实例化对象
Class studentClass = Class.forName("com.bjpowernode.java.bean.Student");
Object obj=studentClass.newInstance();// obj就是student对象。(底层调用无参数构造方法)

//获取no属性(根据属性的名称来获取Field)
Field noFiled = studentClass.getDeclaredField("no");

// 给obj对象(Student对象)的no属性赋值
noFiled.set(obj,22222);//给obj对象的no属性赋值2222

//读取属性的值
Object obj = noFiled.get(obj);

**出现的问题:**私有属性不可以通过上述访问进行赋值访问

**解决方案:**打破封装(缺点),这样设置之后,在外部也可以访问私有属性

Field noFiled = studentClass.getDeclaredField("no");
noField.setAccessible(true);

4、可变长度参数

int…args这就是可变长度参数
语法是:类型…(注意:一定是3个点。)

1、可变长度参数要求的参数个数是:0~N个。
2、可变长度参数在参数列表中必须在最后一个位置上,而且可变长度参数只能有1个。
3、可变长度参数可以当中一个数组来看待

m2(100);
m2(200, "abe");
m2(200, "abc", "def");
m2(200, "abe", "def", "xyz");
m3("ab","de","kk","ff");
String[] strs = {"a","b","c"};
//也可以传1个数组
m3(strs);
m3(new String[]{“我","是","中","国",“人"});


public static void m(int... angs){
	System.out.println("m方法执行了!");
}

//必须在最后,只能有1个。
public static void m2(int a, String... args1){
    
}

public static void m3(String.…. args)
	//args有ength属性,说明args是一个数组!
	//可以将可变长度参数当做一个数组来看。
	for(int i = 0; i < args.length; i++){
		System.out.println(args[i]);
    }
}

5、Method

5.1 通过反射机制获取类的Method的常用方法、

获取所有的Method(包括私有的!)

Method[] methods = userServiceClass.getDeclaredMethods();

获取修饰符列表

Modifier.toString(method.getModifiers());

获取方法的返回值类型

method.getReturnType().getSimpleName();

获取方法名

method.getName();

方法的修饰符列表(一个方法的参数可能会有多个。

Class[] parameterTypes = method.getParameterTypes();
//获取类
Class userServiceClass = Class.forName("com.UserService");
//获取所有的Method(包括私有的!)
Method[] methods = userServiceClass.getDeclaredMethods();
//System.out.println(methods.Length);// 2

// 通历Method
for(Method method:methods){
    //获取修饰符列表
    System.out.println(Modifier.toString(method.getModifiers()));
    //获取方法的返回值类型
    System.out.printIn(method.getReturnType().getSimpleName());
    //获取方法名
    System.out.println(method.getName());
    //方法的修饰符列表(一个方法的参数可能会有多个。)
	Class[] parameterTypes = method.getParameterTypes();
    for(Class parameterType : parameterTypes){
		System.out.println(parameterType.getSimpleName());
    }
}

5.2 通过反射机制访问一个java对象的属性(重点)

不使用反射机制,怎么调用方法

//创建对象
UserService userService = new UserService();
//调用方法
boolean loginSuccess = userService.login( name: "admin", password: "123");
//System.out.printLn(LoginSuccess);
System.out.println(loginSuccess?“登录成功":"登录失数");

使用反射机制来调用一个对象的方法该怎么做?

Class userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");
// 创建对象
Object obj = userServiceClass.newInstance();
// 获取Method(区分Method的有参数名和参数列表)
Method loginMethod = userServiceClass.getDeclaredMethod( "login", String.class);
Method loginMethod2 = userServiceClass.getDeclaredMethod("login", int.class);

//调用方法有几个要素?也需要4要素。
//反射机制中最最最最最重要的一个方法,必须记住。                                 
//四要素:LoginMethod方法
//LoginMethod方法
//obj对象
//"odmin","123”实参
//retVal ue 返回值
obj invoke loginMethod方法(“admin”,“123”)
    
//调用方法
Object retValue = loginMethod.invoke(obj,"admin","123");

6、Construct

6.1 Construct常用的方法

获取无参构造方法

Construct[] constructors = 类名.getDeclaredConstructors();
String s = Modifier.toString(constructor.getModifiers());

6.2 通过反射机制new对象

不使用反射机制怎么创建对象

Vip v1 = new Vip();
Vip v2 = new Vip( 10, "zhangsan", "2001-10-11", true);

使用反射机制怎么创建对象呢?

Class c = Class.forName("com.bjpowernode.java.bean.Vip");

//调用无参数构造方法
Object obj = c.newInstance();//jdk8
System.out.println(obj);
//获取无参数构造方法
Constructor con2 = c.getDeclaredConstructor();//jdk13
Object newObj2 = con2.newInstance();

//调用有参数的构造方法怎么办?
//第一步:先获取到这个有参数的构造方法
Constructor con = c.getDeclaredConstructor(int.class, String.class, String.class,boolean.class);
//第二步:调用构造方法new对象
Object newObj = con.newInstance(110,"jackson","1990-10-11",true)
System.out.println(newObj);

7、获取类的父类和接口

获取String的父类

Class superClass = 类名.getSuperclass();
System.out.println(superClass.getName());

获取所有的接口

//获取String类实现的所有接口(一个类可以实现多个接口。)
Class[] interfaces = stringClass.getInterfaces();
for(Class in:interfaces){
	System.out.println(in.getName());
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖虎不秃头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值