编程语言
首页 > 编程语言> > 什么叫做类的类?如何获取私有的方法?Java反射机制太强大了,详解Java反射机制【Java养成】

什么叫做类的类?如何获取私有的方法?Java反射机制太强大了,详解Java反射机制【Java养成】

作者:互联网

Java学习打卡:第二十二天

内容导航

Java养成计划(打卡第22天)


内容管理

排除学业过于繁忙的时间还有昨天娱乐停更,我们的分享文章已经进行到了22天,再前面的时间里我们一直再扎实java SE的基础,当然这些基础是非常重要的,今天和大家分享的是Java的反射机制,当然这个模块的内容是十分庞大的,我们会慢慢分享

我们开始今天的内容:Java反射机制

Java反射机制

问题引入—数据库介绍

在说反射机制之前,我们知道计算机将数据存储在数据库里面,数据库就像是一个仓库一样,我们常见的数据库是Oracle,MySQL,DB2,SQLSever,SQLLite -----关系型数据库;Redis,MongoDB,HBase-----非关系型数据库

大概分析一下

现在的问题是,一个公司随着业务的扩大需要将所有与MySQL绑定的Java业务全部换成存储量更大的Oracle,你发现java业务中一共几千个文件,那难道要累死累活几天一个个点开文件,将所有的MySOL改成Oracle? 那效率太低下了

集群:一堆完成同一功能的服务器搭建的架构

比如现在用50台服务器作为数据库存储,那用MySOL又划算了,像再把Oracle换成MySOL,这时的文件规模估计又大了许多,所以再点开文件一个一个修改就不可行了

实际上这个绑定不是直接绑定的,在实际开发中往往是采用了Strategy模式,面向接口编程,既然有很多数据库类型,那就不要直接定义成普通类

数据处理部分Service -----操作数据库接口Dao(定义了所有操作数据库的方法)----Dao的具体实现(mySQLDao)-------MySOL

我们在service中就会定义接口的实现类 Dao d = new OracleDao();上转型变量,实现多态,所以这就是所谓的绑定,我么如果真修改就是将所有代码中的子类对象给修改了

这就是 耦合–两个模块之间相互关联

所以说耦合在实际开发中要解耦

那怎么解耦呢,我们可以定义一个文件dao.properties,在这个文件中我们写入dao = MySOLDao;

我们调用实现类对象时就不直接创建对象了,我们就直接读取dao.proprties文件,根据文件内容来创建实现类对象

那这里我们读取到的是文件中的字符串,如何根据字符串来判定我们到底创建哪类对象呢?这就利用到了反射机制

反射机制就是将文件中的内容映射成类

Java反射的介绍

万物皆可对象

我们知道Java文件编译后称为字节码的文件,那这个字节码就可以抽象成类,而字节码是由类得到的,所以我们就可以抽象出

反射:在获取这个类的字节码的基础上来解剖这个类

我们既然知道这是类,怎么使用,如果直接创建对象 new,那么是会报错的,因为这个位于lang包的类代表的是类的类,所以它创建出的对象都是代表一个具体的类,new出来的对象是没有意义的,那我们要如何使用class

class的使用

class是对字节码的抽象,那么某一个具体的类的字节码是不是就是Class的实例码呢,那我们就直接定义一个Class变量,之后将某个具体的类的字节码赋值,那就可以得到具体的类了

public class Luogu extends Thread{
	public static void main(String[] args) {
		Class<String> stz = String.class;//接受类的字节码,这里<>里和后面都是某个具体的类
		System.out.println(stz);
	}
}

得到的结果就是

class java.lang.String

这里就获取到String类的字节码了

那接口可以吗,比如传入List;

也可以的

class java.awt.List //这里它调取了另外一个List

public class Luogu extends Thread{
	public static void main(String[] args) {
		Class<Listener> stz= Listener.class;
		System.out.println(stz);
	}
}

interface java.net.http.WebSocket$Listener

那除了类和接口,那数组可不可以获取字节码呢也是可以的

Class<int[]> stz = int[].class;

得到的结果是

class [I

从这个结果我们可以看出数组也是一个类,所以数组变量也是和其他类的一样都是对象变量

我们获取Class对象–实例码的方式

Object o = "abs";
Class<Object> stz = o.getClass();//得到对象所对应的实例类的字节码

我们其实还可以**利用Class的forName方法来获取,直接通过字符串就能获取到字节码

Class<String> stz = (Class<String>)Class.forName("Date");

这里我们要求的式前后相同,所以要使用一个强制类型转换

但是会出现异常,因为直接给个类型,它找不到的

这里的解决办是我们直接给全路径

public static void main(String[] args) throws ClassNotFoundException {
		@SuppressWarnings("unchecked")
		Class<String> stz = (Class<String>)Class.forName("java.util.Date");
		System.out.println(stz);
	}

运行之后就可以打印出类所对应的字节码了

class java.util.Date

由字符串产生类和对象
Class<String> cla = (Class<String>)Class.forName("java.lang.String");
String str = Cla.newInstane();

这里我们如果正常创建一个Integer对象

Integer in = new Integer(5);

将对像设置为5;那我们就不能使用上的无参的newInstance了,这里就要使用Constructor了

Class<Integer> stz = (Class<Integer>)Class.forName("java.lang.Integer");Constructor<Integer> c = stz.getConstructor(int.class); //获取到了其构造方法Integer in = c.newInstance(5);//由构造方法初始化对象System.out.println(in);

这和上面的语句是等价的,这里我们就是将抽象方法也可以由字节码给反射,但是只能获取到非public的方法

那我们如何获取到非public的构造方法,这时就使用getDeclareConstructor();就可以获取了,传入所需要参数的字节码,就可以构造成功;

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException{		Class<String> stz = (Class<String>)Class.forName("java.lang.String");		Constructor<String> c = stz.getDeclaredConstructor(char[].class,boolean.class);		//Integer in = c.newInstance(5);    	c.setAccessiable(true);//暴力破解,将非法变为合法		System.out.println(c.newInstance(new char[]{'a'}),true);	}

使用该方法就不用区分构造方法的访问权限,不管是public还是非public都可以使用

也就是说类中的访问权限修饰符在反射面前是无效的

获取一个类的所有构造方法的字节码

我们还可以直接使用getDclareConstructors获取类的所有构造方法;

比如String类的

@SuppressWarnings("rawtypes")	public static void main(String[] args) {		Class<String> stz = String.class;		Constructor[] sc = stz.getDeclaredConstructors();		for(Constructor c:sc)//使用的for-each循环		{			System.out.println(c);		}	}

输出的结果是

public java.lang.String(byte[])
public java.lang.String(byte[],int,int)
public java.lang.String(byte[],java.nio.charset.Charset)
public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(byte[],int,int,java.nio.charset.Charset)
java.lang.String(char[],int,int,java.lang.Void)
java.lang.String(java.lang.AbstractStringBuilder,java.lang.Void)
public java.lang.String(java.lang.StringBuilder)
public java.lang.String(java.lang.StringBuffer)
java.lang.String(byte[],byte)
public java.lang.String(char[],int,int)
public java.lang.String(char[])
public java.lang.String(java.lang.String)
public java.lang.String()
public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(byte[],int)
public java.lang.String(byte[],int,int,int)
public java.lang.String(int[],int,int)

这就将String类的所有构造方法给打印出来了

获取一个类的方法(也可以忽略访问权限)

Method m = stz.getDeclaredMethod(“charAt”,int.class);

char c = (char) m.invoke(str,5);

反射的总结

上面杂七杂八说了很多,总的来说,反射就是我们可以通过字节码的方式反射出相应的类,方法,构造方法,属性等

好了,今天的分享就到这里,感觉有些东西没有说清楚,明天会继续分析,望海涵~~

标签:lang,反射,Java,String,太强大,class,Class,java,public
来源: https://blog.csdn.net/a23452/article/details/120557585