JavaSE基础二十二-类加载机制与反射

类加载机制:

类加载分三个步骤:

  1. 加载:将.class字节码文件加载到内存,静态数据转换成运行时数据结构存放到方法区,最后生成这个类的java.lang.Class对象,作为方法区中类数据的访问入口(!!!类加载器的作用!!!)
  2. 链接:验证规范,分配内存,设置类变量初始值默认值(都在方法区进行),将常量池内的常量名引用地址指向直接地址
  3. 初始化:执行类构造器clinit()方法(注意:类构造器是指构造类信息)的过程——>触发初始化,如果有父类,需要先触发父类的初始化
package com.hw.writeannotion;

public class B {

    public static void main(String[] args) {
        A a = new A();
        System.out.println(A.m);
    }
}

class A {
    static {
        System.out.println("A类的静态初始化类...");
        m = 300;
    }

    /*静态变量在第二阶段链接初始化为0*/
    static int m = 100;

    public A() {
        System.out.println("A类的动态初始化块...");
    }
}

哪些情况不会发生类的初始化?

数组, 常量,还有就是静态域不访问或是不访问相关子类的静态变量

 

类加载器分类:

引导类加载器:C++写的,JVM自带的类加载器,负责Java核心库。(代码无法直接获取)

扩展类加载器:负责jre/lib/ext目录下的jar包装入工作库

系统类加载器:负责类与jar包装入工作,最常用

public class B {

    public static void main(String[] args) throws ClassNotFoundException {

        //获取系统类加载器
        ClassLoader loader = ClassLoader.getSystemClassLoader();
        System.out.println(loader); //sun.misc.Launcher$AppClassLoader@18b4aac2

        //获取系统类加载器的父类加载器-->扩展加载器
        ClassLoader parent = loader.getParent();
        System.out.println(parent); //sun.misc.Launcher$ExtClassLoader@1b6d3586

        //获取扩展类加载器的父类加载器-->引导加载器(根加载器)
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);    //null

        //测试当前类是那个加载器加载的
        ClassLoader classLoader = Class.forName("com.hw.writeannotion.B").getClassLoader();
        System.out.println(classLoader);    //sun.misc.Launcher$AppClassLoader@18b4aac2 系统类加载器
    }
}

 

理解类加载机制,对下面的反射学习有好处!

反射:

参考:https://blog.csdn.net/a745233700/article/details/82893076

反射是Java的特征之一,是一种间接操作目标对象的机制,核心是JVM在运行的时候才动态加载类,并且对于任意一个类,都能够知道这个类的所有属性和方法,调用方法/访问属性,不需要提前在编译期知道运行的对象是谁,他允许运行中的Java程序获取类的信息,并且可以操作类或对象内部属性。程序中对象的类型一般都是在编译期就确定下来的,而当我们的程序在运行时,可能需要动态的加载一些类,这些类因为之前用不到,所以没有加载到jvm,这时,使用Java反射机制可以在运行期动态的创建对象并调用其属性,它是在运行时根据需要才加载。

(理解什么是动态加载类?什么是静态加载类

一般new一个构造器,以及下面获取Class类对象的第一,二种方式就是静态加载类

下面获取Class类对象的第三种方式就是动态加载类

 

使用反射的优缺点:


1、优点:

使用反射,我们就可以在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

2、缺点:

(1)反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;

(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题
 

反射的用途:

1、反编译:.class-->.java

2、通过反射机制访问java对象的属性,方法,构造方法等

3、当我们在使用IDE,比如Ecplise时,当我们输入一个对象或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里就是用到反射。

4.反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。

5、例如,在使用Strut2框架的开发过程中,我们一般会在struts.xml里去配置Action,比如

<action name="login" class="org.ScZyhSoft.test.action.SimpleLoginAction" method="execute">   
    <result>/shop/shop-index.jsp</result>           
    <result name="error">login.jsp</result>       
</action>

 

比如我们请求login.action时,那么StrutsPrepareAndExecuteFilter就会去解析struts.xml文件,从action中查找出name为login的Action,并根据class属性创建SimpleLoginAction实例,并用Invoke方法来调用execute方法,这个过程离不开反射。配置文件与Action建立了一种映射关系,当View层发出请求时,请求会被StrutsPrepareAndExecuteFilter拦截,然后StrutsPrepareAndExecuteFilter会去动态地创建Action实例。

比如,加载数据库驱动的,用到的也是反射。
 

Class.forName("com.mysql.jdbc.Driver"); // 动态加载mysql驱动

 

反射大致原理图:

Class类 :

类是谁的对象:所有的类都是java.lang.Class的对象(每个实例对象所属的类都是Class的对象)

注意:

getFilelds方法返回的是数组元素是类内public修饰符所修饰的成员,这些成员包括从父类所继承而来的(public和继承)

getDeclaredFields方法声明在这个类里面的Filed对象构成的数组,包括哪些修饰符类型的呢,public, protected,default,(package) access, and private 所修饰的,其实就差跟你说全部了,但是这里需要注意一个点,继承的不算(该类全部,不包括继承)

 

Class类实践:

package com.sc.classTest;

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Food food = new Food();
		
		//第一种获取Class对象的方式(Class对象就是类)
		Class<Food> c1 = Food.class;
		//第二种获取Class对象的方式
		Class<? extends Food> c2 = food.getClass();
		//第三种获取Class对象的方式
		Class<?> c3 = null;
		try {
			c3 = Class.forName("com.sc.classTest.Food");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println(c1 == c2);
		System.out.println(c2 == c3);//c1=c2=c3
		
		//生成Class对象Food的实例:
		try {
			Food f1 = c1.newInstance();
			Food f2 = c2.newInstance();
			Object f3 = c3.newInstance();
			
			System.out.println(f1 == f2);
			System.out.println(f2 == f3);//f1,f2,f3不是一个对象
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}

class Food{}

 获取类的属性(基本属性获取API基本都有,具体查API):

package com.sc.classTest;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

public class Test2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Class c1 = int.class;
		Class c2 = String.class;
		System.out.println("获取全类名称:" + c1.getName());//获取全类名称:int   (int为基本类型)
		System.out.println("获取不带包名的类名称:" + c1.getSimpleName());//获取不带包名的类名称:int
		System.out.println("获取全类名称:" + c2.getName());//获取全类名称:java.lang.String
		System.out.println("获取不带包名的类名称:" + c2.getSimpleName());//获取不带包名的类名称:String
		
		Method[] m = c2.getMethods();//获取该类的所有public范围的方法,包括父类继承的
		Method[] mm = c2.getDeclaredMethods();//获取该类所有访问权限范围的方法
		System.out.println("String类的所有方法:" + Arrays.toString(m));//String类的所有方法:[public boolean java.lang.String.equals(java.lang.Object), public java.lang.String java.lang.String.toString(), public int java.lang.String.hashCode(), public int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareTo(java.lang.Object), public int java.lang.String.indexOf(java.lang.String,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(int), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public char java.lang.String.charAt(int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public int java.lang.String.compareToIgnoreCase(java.lang.String), public java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public void java.lang.String.getBytes(int,int,byte[],int), public byte[] java.lang.String.getBytes(java.nio.charset.Charset), public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public byte[] java.lang.String.getBytes(), public void java.lang.String.getChars(int,int,char[],int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.CharSequence[]), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.Iterable), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public java.lang.String[] java.lang.String.split(java.lang.String), public java.lang.String[] java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public char[] java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public final native java.lang.Class java.lang.Object.getClass(), public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll(), public default java.util.stream.IntStream java.lang.CharSequence.chars(), public default java.util.stream.IntStream java.lang.CharSequence.codePoints()]
		System.out.println("String类的所有方法:" + Arrays.toString(mm));//String类的所有方法:[public boolean java.lang.String.equals(java.lang.Object), public java.lang.String java.lang.String.toString(), public int java.lang.String.hashCode(), public int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareTo(java.lang.Object), public int java.lang.String.indexOf(java.lang.String,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(int), static int java.lang.String.indexOf(char[],int,int,char[],int,int,int), static int java.lang.String.indexOf(char[],int,int,java.lang.String,int), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public char java.lang.String.charAt(int), private static void java.lang.String.checkBounds(byte[],int,int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public int java.lang.String.compareToIgnoreCase(java.lang.String), public java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public void java.lang.String.getBytes(int,int,byte[],int), public byte[] java.lang.String.getBytes(java.nio.charset.Charset), public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public byte[] java.lang.String.getBytes(), public void java.lang.String.getChars(int,int,char[],int), void java.lang.String.getChars(char[],int), private int java.lang.String.indexOfSupplementary(int,int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.CharSequence[]), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.Iterable), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(java.lang.String), static int java.lang.String.lastIndexOf(char[],int,int,java.lang.String,int), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.lastIndexOf(int,int), static int java.lang.String.lastIndexOf(char[],int,int,char[],int,int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), private boolean java.lang.String.nonSyncContentEquals(java.lang.AbstractStringBuilder), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public java.lang.String[] java.lang.String.split(java.lang.String), public java.lang.String[] java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public char[] java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim()]
		
		System.out.println("获取方法名:" + m[0].getName());//获取方法名:equals
		System.out.println("获取方法返回值类型:" + m[0].getReturnType());//获取方法返回值类型:boolean
		System.out.println("获取方法参数列表类型:" + Arrays.toString(m[0].getParameterTypes()));//获取方法参数列表类型:[class java.lang.Object]
		System.out.println("获取方法参数列表参数:" + Arrays.toString(m[0].getParameters()));//获取方法参数列表参数:[java.lang.Object arg0]
		
		Field[] f = c2.getFields();//获取该类的所有public范围的成员变量,包括父类继承的
		Field[] ff = c2.getDeclaredFields();//获取该类所有访问权限范围的成员变量
		System.out.println("String类的所有成员变量:" + Arrays.toString(f));
		System.out.println("String类的所有成员变量:" + Arrays.toString(ff));
		
		System.out.println("获取成员变量名称:" + f[0].getName());//获取成员变量名称:CASE_INSENSITIVE_ORDER
		System.out.println("获取成员变量类型:" + f[0].getType());//获取成员变量类型:interface java.util.Comparator
		
		Constructor[] constructors = c2.getConstructors();//获取该类的所有public范围的构造方法
		Constructor[] constructors2 = c2.getDeclaredConstructors();//获取该类的所有public范围的构造方法
		System.out.println("String类的所有构造方法:" + Arrays.toString(constructors));
		System.out.println("String类的所有构造方法:" + Arrays.toString(constructors2));
		
		System.out.println("获取构造器名:" + constructors[0].getName());//获取构造器名:java.lang.String
	}

}

使用方法进行反射操作_______调用类实例的方法(方法实例.invoke("类实例",参数列表):

先获取方法对象,在用该对象调用invoke

        Class<String> c2 = String.class;
        try {
			Method xx = c2.getMethod("equals", Object.class);
			System.out.println("你好".equals("你好"));//true
			System.out.println(xx.invoke("你好", "你好"));//true(和上面效果相同)
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

获取当前类的两种方式:

适用于非静态方法:this.getClass().getName()

适用于静态方法:Thread.currentThread().getStackTrace()[1].getClassName()

 

 

利用反射执行配置文件参数:

package com.sc.classTest;

public class Test33 {

	public void print() {
		System.out.println("利用反射读取配置文件-------已完成...");
	}
}







package com.sc.classTest;

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

public class Test3 {

	public static void main(String[] args) throws ClassNotFoundException, FileNotFoundException, IOException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
		// TODO Auto-generated method stub
		Class<?> class1 = Class.forName(getValue("className"));
		Method m = class1.getMethod(getValue("methodName"));
		m.invoke(class1.newInstance());
	}
	
	private static String getValue(String key) throws FileNotFoundException, IOException {
		Properties p = new Properties();
		FileInputStream f = new FileInputStream("test.properties");
		p.load(f);
		f.close();
		return p.getProperty(key);
	}

}

结果:

利用反射读取配置文件-------已完成...

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值