Day16基礎(chǔ)不牢地動(dòng)山搖-Java基礎(chǔ)
1、反射機(jī)制
反射機(jī)制如果只是針對(duì)普通開發(fā)者而言意義不大,一般都是作為一些系統(tǒng)的構(gòu)架設(shè)計(jì)去使用的,包括以后學(xué)習(xí)的開源框架,那么幾乎都是反射機(jī)制。
1.1 認(rèn)識(shí)反射
反射指的是對(duì)象的反向處理操作,就首先觀察以下“正”的操作,在默認(rèn)情況下,必須先導(dǎo)入一個(gè)包才能產(chǎn)生類的實(shí)例化對(duì)象。
所謂的“反”根據(jù)對(duì)象來取得對(duì)象的來源信息,“反”的操作的本來來源就是Object的一個(gè)方法。
- 取得class對(duì)象:public final 類<?> getClass() 該方法返回的一個(gè)Class類的對(duì)象,這個(gè)Class描述的就是類。
package com.day16.demo;
import java.util.Date;
import javafx.scene.chart.PieChart.Data;
public class FanShedemo {
public static void main(String[] args) {
Date date = new Date();
//java.util.Date
System.out.println(date.getClass().getName());
}
}
此時(shí)通過對(duì)象的確對(duì)象的來源,就是“反”的本質(zhì)。在反射的背后不在是一個(gè)對(duì)象,而是對(duì)象身后的來源。
而這個(gè)getClass()方法返回的對(duì)象是Class類對(duì)象,所以這個(gè)Class就是所有反射操作的源頭,但是在講解其真正使用之前還有一個(gè)需要先解釋的問題,既然Class是所有反射操作的源頭,那么這個(gè)類肯定是最為重要的,而如果要想取得這個(gè)類的實(shí)例化對(duì)象,java中定義了三種方式:
方式一:通過Object類的getClass()方法取得
package com.day16.demo;
import java.util.Date;
public class FanShedemo {
public static void main(String[] args) {
Date de = new Date();//正著操作
Class<?> cla =de.getClass();//取得class對(duì)象
System.out.println(cla.getName());//反著來
}
}
方式二:通過“類.Class”取得
package com.day16.demo;
import java.util.Date;
public class FanShedemo {
public static void main(String[] args) {
Date de = new Date();//正著操作
Class<?> cla =Date.class;//取得class對(duì)象
System.out.println(cla.getName());//反著來
}
}
方式三:使用Class內(nèi)部定義的一個(gè)static方法
package com.day16.demo;
import java.util.Date;
public class FanShedemo {
public static void main(String[] args) throws Exception{
Date de = new Date();//正著操作
Class<?> cla =Class.forName("java.util.Date");//取得class對(duì)象
System.out.println(cla.getName());//反著來
}
}
在以上給出的三個(gè)方法會(huì)發(fā)現(xiàn)一個(gè)神奇的地方,除了第一種形式會(huì)產(chǎn)生Date實(shí)例化對(duì)象,而第二種和第三種沒有
實(shí)例化取得對(duì)象。于是取得Class類對(duì)象有一個(gè)最直接的好處:可以直接通過反射實(shí)例化對(duì)象,在Class類中有一個(gè)方法:
- **通過反射實(shí)例化對(duì)象:**public T newInstance() throws InstantiationException IllegalAccessException
反射實(shí)例化對(duì)象
package com.day16.demo;
import java.util.Date;
public class FanShedemo {
public static void main(String[] args) throws Exception{
Class<?> cla =Class.forName("java.util.Date");//取得class對(duì)象
Object o = cla.newInstance();//取得Date對(duì)象
System.out.println(o);
}
}

現(xiàn)在可以發(fā)現(xiàn),對(duì)于對(duì)象的實(shí)例化操作,除了使用關(guān)鍵字new之外又多了一個(gè)反射機(jī)制操作,而且這個(gè)操作要比之前使用的new復(fù)雜一些,可是有什么用呢?
對(duì)于程序的開發(fā)模式之前一直強(qiáng)點(diǎn):盡量減少耦合,而減少耦合的最好的做法是使用接口,但是就算使用了接口也逃不出關(guān)鍵字new,多以實(shí)際上new是耦合的關(guān)鍵元兇。
1.2 取得父類信息
反射可以做出一個(gè)對(duì)象所具備的所有操作行為,而且最關(guān)鍵的是這一切的操作都可以基于Object類型進(jìn)行。
在Java里面任何的程序類實(shí)際上都一定會(huì)有一個(gè)父類,在Class類里面就可以通過此類方式來取得父類或者是實(shí)現(xiàn)的父接口,有如下兩個(gè)方法提供:
| public 軟件包 getPackage() | 取得類的包名稱 |
| public 類<? super T> getSuperclass() | 取得父類的Class對(duì)象 |
| public 類<?>[] getInterfaces() | 取得父接口 |
取得類的相關(guān)信息
package com.day16.demo;
import java.util.Arrays;
interface IFruit{}
interface IMessage{}
class Person implements IFruit,IMessage{
}
public class FanShedemo {
public static void main(String[] args) throws Exception{
Class<?> cls = Person.class;
System.out.println(cls.getPackage().getName());
System.out.println(cls.getSuperclass().getName());
Class<?> itf[] = cls.getInterfaces();
System.out.println(Arrays.toString(itf));
}
}
通過我們反射可以取得類結(jié)構(gòu)上的所有關(guān)鍵信息。
1.3 反射調(diào)用構(gòu)造
一個(gè)類可以存在多個(gè)構(gòu)造方法,如果我們要想取得類中構(gòu)造的調(diào)用,我們就可以使用Class類提供的兩個(gè)方法
| public Constructor getConstructor(類<?>… parameterTypes) throws NoSuchMethodException, SecurityException |
取得指定參數(shù)類型的構(gòu)造方法 |
| public Constructor<?>[] getConstructors() throws SecurityException |
取得類中的所有構(gòu)造 |
以上兩個(gè)方法的返回類型都是java.lang.reflect.Constructor類的實(shí)例化對(duì)象,這個(gè)類里面關(guān)注一個(gè)方法,實(shí)例化對(duì)象:public T newInstance(Object… initargs) throws InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException
取得類中所有構(gòu)造方法的信息—利用Constructor類中的toString()方法取得了構(gòu)造方法的完整信息
package com.day16.demo;
import java.lang.reflect.Constructor;
import java.util.Arrays;
class Person {
public Person(){}
public Person(String name){}
public Person(String name , int age){}
}
public class FanShedemo {
public static void main(String[] args) throws Exception{
Class<?> cls = Person.class;
Constructor<?> cst [] = cls.getConstructors();
for (int i = 0; i < cst.length; i++) {
System.out.println(cst[i]);
}
}
}
如果使用getName()方法就比較麻煩
自己拼湊構(gòu)造方法操作
package com.day16.demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.Arrays;
class Person {
public Person() throws Exception,RuntimeException{}
public Person (String name) throws Exception,RuntimeException{}
public Person(String name , int age) throws Exception,RuntimeException{}
}
public class FanShedemo {
public static void main(String[] args) throws Exception{
Class<?> cls = Person.class;
Constructor<?> cst [] = cls.getConstructors();
for (int i = 0; i < cst.length; i++) {
System.out.print(Modifier.toString(cst[i].getModifiers()) + " ");
System.out.print(cst[i].getName() + "(");
Class <?> params [] = cst[i].getParameterTypes();
for (int j = 0; j < params.length; j++) {
System.out.print(params[j].getName());
if(j < params.length - 1){
System.out.print(",");
}
}
System.out.print(")");
Class<?> exps [] = cst[i].getExceptionTypes();
if(exps.length > 0){
System.out.print(" throws ");
for (int j = 0; j < exps.length; j++) {
System.out.print(exps[j].getName());
if(j < exps.length - 1){
System.out.print(",");
}
}
}
System.out.println();
}
}
}
學(xué)習(xí)Constructor類目的并不是分析方法的組成,最需要的關(guān)注就是問題的結(jié)論:在定義簡單的java類一定要保留一個(gè)無參構(gòu)造。
觀察沒有無參構(gòu)造的方法
package com.day16.demo;
import java.lang.reflect.Constructor;
class Per{
private String name;
private int age;
public Per(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
return "Per [name=" + name + ", age=" + age + "]";
}
}
public class FanShedemo {
public static void main(String[] args) throws Exception{
Class<?> cls = Per.class;//取得class對(duì)象
Object obj=cls.newInstance();
}
}
Exception in thread "main" java.lang.InstantiationException: com.day16.demo.Person at java.lang.Class.newInstance(Class.java:427) at com.day16.demo.FanShedemo.main(FanShedemo.java:19) Caused by: java.lang.NoSuchMethodException: com.day16.demo.Person.<init>() at java.lang.Class.getConstructor0(Class.java:3082) at java.lang.Class.newInstance(Class.java:412) ... 1 more
此時(shí)運(yùn)行的時(shí)候出現(xiàn)了錯(cuò)誤提示“java.lang.InstancetiationException”因?yàn)橐陨系姆绞绞褂梅瓷鋵?shí)例化對(duì)象時(shí)需要的是類之中提供無參構(gòu)造方法,但是現(xiàn)在既然沒有了無參構(gòu)造方法,那么就必須明確的找到一個(gè)構(gòu)造方法。
通過Constructor類實(shí)例化對(duì)象
package com.day16.demo;
import java.lang.reflect.Constructor;
class Per{
private String name;
private int age;
public Per(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
return "Per [name=" + name + ", age=" + age + "]";
}
}
public class FanShedemo2 {
public static void main(String[] args) throws Exception{
Class<?> cls = Per.class;//取得class對(duì)象
//現(xiàn)在明確表示取得指定參數(shù)類型的構(gòu)造方法對(duì)象
Constructor<?> cont = cls.getConstructor(String.class,int.class);
System.out.println(cont.newInstance("張三",19));
}
}
一行寫簡單Java類要寫無參構(gòu)造,以上內(nèi)容就只需要了解就可以了。
1.4 反射調(diào)用方法
當(dāng)取得了一個(gè)類之中的實(shí)例化對(duì)象之后,下面最需要調(diào)用的肯定是類之中的方法,所以可以繼續(xù)使用Class類取得一個(gè)類中所定義的方法定義:
| **public Method[] getMethods() throws SecurityException |
取得全部方法 |
| public Method getMethod(String name,Class<?>… parameterTypes) throws NoSuchMethodException, SecurityException |
取得指定方法 |
發(fā)現(xiàn)以上的方法返回的都是java.lang.Method類的對(duì)象。
取得一個(gè)類之中全部定義的方法
package com.day16.demo;
import java.lang.reflect.Method;
class Student{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class FanShedemo3 {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.day16.demo.Student");
Method met [] = cls.getMethods();
for (int i = 0; i < met.length; i++) {
System.out.println(met[i]);
}
}
}
但是取得類Method類對(duì)象最大的作用不在于方法的列出(方法的列出都在開發(fā)工具上使用了),但是對(duì)于取得了Method類對(duì)象之后還有一個(gè)最大的功能,就是可以利用反射調(diào)用類的方法:
調(diào)用方法:public Object invoke(Object obj,Object… args) throws IllegalAccessException,IllegalArgumentException,InvocationTargetException之前調(diào)用類中的方法的時(shí)候使用的都是“對(duì)象.方法”,但是現(xiàn)在有了反射之后,可以直接利用Object類調(diào)用指定子類的操作方法。(同事解釋一下,為什么setter,和getter方法的命名要求如此嚴(yán)格)。
利用反射調(diào)用Student類之中的setName(),getName()方法。
package com.day16.demo;
import java.lang.reflect.Method;
class Student{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class FanShedemo3 {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.day16.demo.Student");
Object obj = cls.newInstance();//實(shí)例化對(duì)象
Method met [] = cls.getMethods();
Method setM=cls.getMethod("setName",String.class);//通過反射構(gòu)建方法
Method getM=cls.getMethod("getName");
setM.invoke(obj, "小張同學(xué)");//鍵值對(duì)的形式傳遞參數(shù)此過程相當(dāng)于setM
Object result = getM.invoke(obj);
System.out.println(result);
}
}
在日后所有的技術(shù)開發(fā)中,簡單Java類都是如此應(yīng)用,多以必須按照標(biāo)準(zhǔn)進(jìn)行。
1.5 反射調(diào)用成員
個(gè)組成部分就是成員(Field,也可以稱為屬性),如果要通過反射取得類的成員可以使用方法如下:
取得本類的全部成員:public Field[] getDeclaredFields() throws SecurityException
取得指定成員:public Field getDeclaredField(String name)throws NoSuchFieldException, SecurityException
取得本類全部成員
package com.day16.demo;
import java.lang.reflect.Field;
class Person4{
private String name;
}
public class FanShedemo4 {
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("com.day16.demo.Person4");
Object obj = cls.newInstance();
Field[] fields = cls.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
//private java.lang.String com.day16.demo.Person4.name
System.out.println(fields[i]);
}
}
}
但是找到了Field實(shí)際上就找到了一個(gè)很有意思的操作,在Field類之中提供了兩個(gè)方法:
設(shè)置屬性內(nèi)容(類似于:對(duì)象.屬性=內(nèi)容):public void set(Object obj,Object value) throws IllegalArgumentException,IllegalAccessException
取得屬性內(nèi)容(類似于:對(duì)象.屬性):public Object get(Object obj) throws IllegalArgumentException,IllegalAccessException
可是從類的開發(fā)要求而言,一直都強(qiáng)調(diào)類之中的屬性必須封裝,所以現(xiàn)在調(diào)用之前要想辦法解除封裝。
- 解除封裝(重點(diǎn)):public void setAccessible(boolean flag)throws SecurityException
利用反射操作類中的屬性
package com.day16.demo;
import java.lang.reflect.Field;
class Person4{
private String name;
}
public class FanShedemo4 {
public static void main(String[] args) throws Exception{
Class<?> cls = Class.forName("com.day16.demo.Person4");
Object obj = cls.newInstance();
Field field = cls.getDeclaredField("name");//得到Person4成員變量
//由于Person4設(shè)置的屬性是私有屬性,所以是無法操作的
field.setAccessible(true);///解決封裝
field.set(obj, "小張");
System.out.println(field.get(obj));
}
}
雖然反射機(jī)制運(yùn)行直接操作類之中的屬性,可是不會(huì)有任何一種程序直接操作屬性,都會(huì)通過setter,getter方法。

1.6 反射與簡單Java類—單級(jí)VO操作原理
如果現(xiàn)在又一個(gè)簡單Java類,那么這個(gè)簡單Java類中的屬性按照原始的做法一定要通過setter才可以設(shè)置,取得肯定繼續(xù)使用getter(不關(guān)注此處)。
Emp.java
package com.day16.vo;
public class Emp {
private String ename;
private String job;
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public String toString() {
return "Emp [ename=" + ename + ", job=" + job + "]";
}
}
EmpAction.java
package com.day16.action;
import com.day16.vo.Emp;
public class EmpAction {
private Emp emp = new Emp();
public void setValue(String val ){//設(shè)置屬性內(nèi)容
this.emp.setEname("SMI");
this.emp.setJob("STRACK");
}
public Emp getEmp(){
return emp;
}
}
EmpDemo.java
package com.day16.demo;
import com.day16.action.EmpAction;
public class EmpDemo {
public static void main(String[] args) {
String value="emp.ename:smi|emp.job:strack";
EmpAction action = new EmpAction();
action.setValue(value);
System.out.println(action.getEmp());
}
}

1.7 單極自動(dòng)VO設(shè)置實(shí)現(xiàn)
現(xiàn)在所有操作都是通過TestDemo類調(diào)用EmpAciton類實(shí)現(xiàn)的,而EmpAciton類的主要作用在于定位要操作屬性的類型。同時(shí)該程序應(yīng)該符合所有的簡單Java類開發(fā)形式,也就意味著我們的設(shè)計(jì)必須有一個(gè)單獨(dú)的類來實(shí)現(xiàn)。
由于Bean的處理操作肯定需要重復(fù)出去對(duì)象信息,所以我們還需要準(zhǔn)備兩個(gè)程序類:StringUtils,負(fù)責(zé)字符串的操作,畢竟屬性的首字母需要大寫處理,而后在寫一個(gè)對(duì)象的具體操作(取得對(duì)象、設(shè)置對(duì)象內(nèi)容)。
工具類—BeanOperation.java
package com.day16.util;
/**
* @author 張晟睿
* 本類主要負(fù)責(zé)實(shí)現(xiàn)自動(dòng)VO匹配處理操作,本身不需要通過實(shí)例化對(duì)象完成,所以構(gòu)造方法私有化
*/
public class BeanOperation {
private BeanOperation(){}
/**
* @param actionObject 表示當(dāng)前發(fā)出設(shè)置請(qǐng)求的程序類的當(dāng)前對(duì)象
* @param msg 所有屬性的具體內(nèi)容,格式“屬性名稱:內(nèi)容|屬性名稱:內(nèi)容”
*
*/
public static void setBeanValue(Object actionObject,String msg) throws Exception{
String result [] = msg.split("\\|");
for (int i = 0; i < result.length; i++) {
//需要針對(duì)于給定的屬性名稱和內(nèi)容進(jìn)行一次拆分
String temp[] = result[i].split(":");
String attribute = temp[0];//屬性名稱,包括“XxxAction屬性和具體的簡單AJava類的屬性”
String value = temp[1];//接收具體的內(nèi)容屬性
String fields [] = attribute.split("\\.");
Object currentObject = ObjectUtils.getObject(actionObject,fields[0]);
ObjectUtils.setObjectValue(currentObject, fields[1], value);
}
}
}
工具類—StringUtils.java
package com.day16.util;
/**
* @author 張晟睿
* 針對(duì)于字符串進(jìn)行處理操作
*/
public class StringUtils {
private StringUtils(){}
/**
* @param str
* @return 返回首字母大寫
* 首字母大寫
*/
public static String initcap(String str){
return str.substring(0,1).toUpperCase() + str.substring(1);
}
}
工具類—ObjectUtils.java
package com.day16.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author 張晟睿
* 本類的主要功能是根據(jù)屬性名稱調(diào)用響應(yīng)類中g(shù)etter、setter方法
*/
public class ObjectUtils {
private ObjectUtils(){}
/**
* 根據(jù)指定的類對(duì)象,設(shè)置類中的屬性
* @param wrapo 屬性所在類的實(shí)例化對(duì)象
* @param attribute 屬性名稱
* @param value 屬性內(nèi)容
*/
public static void setObjectValue(Object wrapo,String attribute, String value) throws Exception{
//調(diào)用指定屬性的Field對(duì)象,母的是取得對(duì)象類型,如果沒有屬性也就是說該操作無法繼續(xù)
Field field = wrapo.getClass().getDeclaredField(attribute);//判斷屬性是否存在
if(field == null){
field = wrapo.getClass().getField(attribute);
}
if(field == null){//兩次操作都無法取得對(duì)應(yīng)的成員變量
return ;//該屬性一定不存在
}
String methodName = "set" + StringUtils.initcap(attribute);
Method method = wrapo.getClass().getMethod(methodName,field.getType());
method.invoke(wrapo, value);
}
/**
* 負(fù)責(zé)調(diào)用指定類中g(shù)etter方法
* @param wrapo 表示要調(diào)用方法的所在對(duì)象
* @param attribute 表示屬性名稱
* @return 調(diào)用對(duì)象的結(jié)果
*/
public static Object getObject(Object wrapo,String attribute) throws Exception{
String methodName = "get" + StringUtils.initcap(attribute);//定義getter方法
//調(diào)用指定屬性的Field對(duì)象,母的是取得對(duì)象類型,如果沒有屬性也就是說該操作無法繼續(xù)
Field field = wrapo.getClass().getDeclaredField(attribute);
if(field == null){
field = wrapo.getClass().getField(attribute);
}
if(field == null){//兩次操作都無法取得對(duì)應(yīng)的成員變量
return null;//該屬性一定不存在
}
Method method = wrapo.getClass().getMethod(methodName);
return method.invoke(wrapo);
}
}
EmpAction.java
package com.day16.action;
import com.day16.util.BeanOperation;
import com.day16.vo.Emp;
public class EmpAction {
private Emp emp = new Emp();
public void setValue(String val ){//設(shè)置屬性內(nèi)容
//之所以傳遞this,主要將EmpAction的類對(duì)象傳遞方法里面
//因?yàn)榻o定的標(biāo)記:emp.ename:smith,而emp應(yīng)該對(duì)象的是getEmp()方法
try {
BeanOperation.setBeanValue(this, val);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Emp getEmp(){
return emp;
}
}

1.8 反射與簡單Java類—多級(jí)VO設(shè)置實(shí)現(xiàn)

現(xiàn)在假設(shè)一個(gè)雇員屬于一個(gè)部門,一個(gè)部門屬于一個(gè)公司,一個(gè)公司屬于一個(gè)城市,一個(gè)城市屬于一個(gè)省份,一個(gè)省份屬于一個(gè)國家,這種類似關(guān)系都可以通過字符串實(shí)現(xiàn)多級(jí)配置。
修改Dept.java類
public class Dept {
private String dname;
private String loc;
private Company company = new Company();
}
修改Emp.java類
public class Emp {
private String ename;
private String job;
private Dept dept = new Dept();
}
此時(shí)所有的引用關(guān)系上都自動(dòng)進(jìn)行了對(duì)象實(shí)例化。而現(xiàn)在程序希望可以滿足于單級(jí)和多級(jí)。

修改BeanOperation.java
package com.day16.util;
/**
* @author 張晟睿
* 本類主要負(fù)責(zé)實(shí)現(xiàn)自動(dòng)VO匹配處理操作,本身不需要通過實(shí)例化對(duì)象完成,所以構(gòu)造方法私有化
*/
public class BeanOperation {
private BeanOperation(){}
/**
* @param actionObject 表示當(dāng)前發(fā)出設(shè)置請(qǐng)求的程序類的當(dāng)前對(duì)象
* @param msg 所有屬性的具體內(nèi)容,格式“屬性名稱:內(nèi)容|屬性名稱:內(nèi)容”
*
*/
public static void setBeanValue(Object actionObject,String msg) throws Exception{
String result [] = msg.split("\\|");
for (int i = 0; i < result.length; i++) {
//需要針對(duì)于給定的屬性名稱和內(nèi)容進(jìn)行一次拆分
String temp[] = result[i].split(":");
String attribute = temp[0];//屬性名稱,包括“XxxAction屬性和具體的簡單AJava類的屬性”
String value = temp[1];//接收具體的內(nèi)容屬性
String fields [] = attribute.split("\\.");//拆分出屬性信息
if(fields.length > 2){//多級(jí)配置
//如果要想多級(jí)確定出屬性的操作對(duì)象,那么應(yīng)該一層找出每一個(gè)getter方法返回的內(nèi)容
Object currentObject = actionObject;//確定當(dāng)前要操作的對(duì)象
for (int j = 0; j < fields.length - 1; j++) {//對(duì)應(yīng)getter返回對(duì)象
currentObject = ObjectUtils.getObject(currentObject, fields[j]);
}
ObjectUtils.setObjectValue(currentObject, fields[fields.length - 1], value);
}else{//單級(jí)配置
Object currentObject = ObjectUtils.getObject(actionObject,fields[0]);
ObjectUtils.setObjectValue(currentObject, fields[1], value);
}
}
}
}
定義TestEmpDemo.java
package com.day16.demo;
import com.day16.action.EmpAction;
public class TestEmpDemo {
public static void main(String[] args) {
String value="emp.ename:smi|emp.job:strack|emp.dept.dname:財(cái)務(wù)部|emp.dept.company.name:zsr|emp.dept.company.address:北京";
EmpAction action = new EmpAction();
action.setValue(value);
System.out.println(action.getEmp());
}
}
這樣的程序才可以正常使用,屬于無限級(jí)配置。
2、ClassLoader類加載器
Class類描述的是類的整個(gè)信息,在Class類中提供的forName()方法它所能處理的只是通過CLASSPATH配置的路徑進(jìn)行加載,而我們的類加載的路徑可能是網(wǎng)絡(luò)、文件、數(shù)據(jù)庫。這是ClassLoader類主要作用。
2.1 認(rèn)識(shí)類加載器
首先Class觀察一個(gè)方法:public ClassLoader getClassLoader();
編寫簡單的反射程序,觀察ClassLoader的存在
package com.day17.demo;
class Member{//自定義類一定在CLASSPATH之中
}
public class TestDemo1 {
public static void main(String[] args) {
Class<?> cls = Member.class;
System.out.println(cls.getClassLoader());
System.out.println(cls.getClassLoader().getParent());
System.out.println(cls.getClassLoader().getParent().getParent());
}
}
/*
sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@15db9742
null
*/
出現(xiàn)兩個(gè)加載器AppClassLoader(應(yīng)用程序類加載器)、ExtClassLoader(擴(kuò)展類加載器)。

對(duì)于第三方程序類庫除了CLASSPATH之外,實(shí)際上在java里面還有一個(gè)加載目錄:C:\ProgramFiles\Java\jdk1.8.0_241\jre\lib\ext

觀察類我們發(fā)現(xiàn)ClassLoader里有一個(gè)方法:public 類<?> loadClass(String name) throws ClassNotFoundException,進(jìn)行類的加載操作處理。
2.2 自定義ClassLoader
**實(shí)現(xiàn)文件的類加載器 **
package com.day17.demo;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
class MyClassLoader extends ClassLoader{
/**
* 實(shí)現(xiàn)一個(gè)自定義的類加載器,傳入類名稱后,通過指定文件路徑加載
* @param className
* @return
* @throws Exception
*/
public Class<?> loadData(String className) throws Exception{
byte classDate [] = this.loadClassData();
return super.defineClass(className, classDate, 0, classDate.length);
}
/**
* 通過指定文件路徑進(jìn)行類的文件加載,進(jìn)行二進(jìn)制讀取
* @return
* @throws Exception
*/
private byte [] loadClassData() throws Exception{
InputStream input = new FileInputStream("f:" + File.separator + "java" + File.separator + "Member.class");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte [] data = new byte [20];//定義讀取的緩沖區(qū)
int temp = 0;
while((temp = input.read(data)) != -1){
bos.write(data,0,temp);
}
byte ret [] = bos.toByteArray();
input.close();
bos.close();
return ret;
}
}
public class ClassLoaderDemo {
public static void main(String[] args) throws Exception{
Class<?> cls = new MyClassLoader().loadData("com.day17.test.Member");
System.out.println(cls.newInstance());
}
}
類加載器給我們用戶最大的幫助就是在于可以通過動(dòng)態(tài)的路徑實(shí)現(xiàn)類的加載處理操作。
到此這篇關(guān)于Day16基礎(chǔ)不牢地動(dòng)山搖-Java基礎(chǔ)的文章就介紹到這了,更多相關(guān)Java基礎(chǔ)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決RedisTemplate存儲(chǔ)至緩存數(shù)據(jù)出現(xiàn)亂碼的情況
這篇文章主要介紹了解決RedisTemplate存儲(chǔ)至緩存數(shù)據(jù)出現(xiàn)亂碼的情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-03-03
Java中HTTP接口請(qǐng)求重試的實(shí)現(xiàn)方式
HTTP接口請(qǐng)求重試是指在請(qǐng)求失敗時(shí),再次發(fā)起請(qǐng)求的機(jī)制,在實(shí)際應(yīng)用中,由于網(wǎng)絡(luò)波動(dòng)、服務(wù)器故障等原因,HTTP接口請(qǐng)求可能會(huì)失敗,為了保證系統(tǒng)的可用性和穩(wěn)定性,需要對(duì)HTTP接口請(qǐng)求進(jìn)行重試,所以本文給大家介紹了HTTP接口請(qǐng)求重試的實(shí)現(xiàn)方式,需要的朋友可以參考下2024-01-01
帶你輕松搞定Java面向?qū)ο蟮木幊?-數(shù)組,集合框架
Java是面向?qū)ο蟮母呒?jí)編程語言,類和對(duì)象是 Java程序的構(gòu)成核心。圍繞著Java類和Java對(duì)象,有三大基本特性:封裝是Java 類的編寫規(guī)范、繼承是類與類之間聯(lián)系的一種形式、而多態(tài)為系統(tǒng)組件或模塊之間解耦提供了解決方案2021-06-06
SpringDataJpa如何使用union多表分頁條件查詢
這篇文章主要介紹了SpringDataJpa如何使用union多表分頁條件查詢,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02

