Java教程

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

本文主要是介绍什么叫做类的类?如何获取私有的方法?Java反射机制太强大了,详解Java反射机制【Java养成】,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Java学习打卡:第二十二天

内容导航

  • Java学习打卡:第二十二天
    • 内容管理
      • Java反射机制
        • 问题引入---数据库介绍
        • Java反射的介绍
          • class的使用
          • 由字符串产生类和对象
          • 获取一个类的所有构造方法的字节码
          • 获取一个类的方法(也可以忽略访问权限)
      • 反射的总结

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


内容管理

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

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

Java反射机制

问题引入—数据库介绍

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

大概分析一下

  • SQLLite ,是Apache旗下的一款微型数据库,它所存储的数据非常小,占用内存也很小,相比Oracle就很小,它的应用场景就是比如手机等嵌入式设备,在实际开发中用到的比较少
  • DB2,是IBM旗下的数据库,市场占有率不高,主要应用于金融领域,所以开发中还是使用的比较少
  • SQLServer:微软旗下数据库,SQLsever因此与C/C++的兼容性更高,在Java中使用就需要做很多准备工作,所以在java中也很少使用
  • MySQL:也是Apache,是轻量级,并且是免费的,所以很多公司都会使用
  • Oracle:正量级,存储量庞大,但是会收费,并且所占内存大

现在的问题是,一个公司随着业务的扩大需要将所有与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文件编译后称为字节码的文件,那这个字节码就可以抽象成类,而字节码是由类得到的,所以我们就可以抽象出

  • Class -------代表类的类
  • Package-------代表包的类
  • Method ------代表方法的类
  • Filed-------代表属性的类
  • Constructor-----代表构造方法的类
  • Annotation------代表注解的类

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

我们既然知道这是类,怎么使用,如果直接创建对象 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对象–实例码的方式

  • 像上面的演示一样利用.class的方式
  • 利用Object类里面的getClass() 对象.getClass
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的forname就可以得到一个字符串所对应的类
  • 之后利用存储类的字节码的变量使用.newInstance()方法,就可以按照无参的构造方法创建一个该类的一个实例对象,用一个该变量去接受(但是这里只能就使用无参的构造方法) 那我们要使用含参的构造方法就要使用上面的C欧尼structor类
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);

反射的总结

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

  • 我们的获取类的字节码的方式有三种,一种是直接类名.class;还有就是由具体的对象获取 Object obj; obj.getClass就可以获取字节码;还有就是使用class类的forName方法,但是这种方法我们需要注意就是要将类名加在<>里,还有就是要给完全路径

  • 我们获取到类的字节码,我们就可以根据字节码获取到相关的Constructor,Method对象, 比如存储字节码的是stz, 那么通过stz.getDeclaredConstructor()就可以获取到相关的含参构造方法,对其实现就newInstance就可以使用

  • 同理我们使用方法也可以根据stz,stz.getDeclaredMethod()就可以获取方法,只是在获取方法时要传入参数的字节码,比如int.class ,String.class;实现就invoke()—传入具体的参数就可

  • 最关键的就是我们获取的方法都是不区分访问权限的,以前普通的方法或许存在不可见的问题,但是反射直接可以暴力破解 setAccessiable(true);这样我们就可以获取到私有的方法了

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

这篇关于什么叫做类的类?如何获取私有的方法?Java反射机制太强大了,详解Java反射机制【Java养成】的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!