随笔都是学习笔记
随笔仅供参考,为避免笔记中可能出现的错误误导他人,请勿转载。

反射:

反射之中的所有核心操作都是通过Class类展开的,可以说Class类是反射的根源所在,那么获取Class类的实例化对象,可以采用三种方式实现;

首先观察java.lang.Class类的定义:

【JDK1.0】:public final class Class<T> extends Object implements Serializable,GenericDeclaration, Type, AnnotatedElement;

从JDK1.5开始,Class类的定义可以使用泛型进行标记,这样的用法主要是希望可以避免所谓的向下转型;

通过三种操作观察三种实例化形式:

【Object类支持】Object类可以根据实例化对象获取Class对象:

但是这种方式有一个不是缺点的缺点:如果现在只是想获取Class类对象,则必须产生指定类后才能获取。

 

public final Class<?> getClass();
class Person{
}
public class MAIN {
    public static void main(String[] args) {
        Person pr = new Person();   // 已经存在有指定类的实例化对象
        Class<?> cls = pr.getClass();
        System.out.println(cls.getName());  // 获取的是类的完整名称
    }
}

 

 

【JVM直接支持】:采用“类.Class”直接实例化:

  - 特点:如果是使用这种方式,那么必须导入程序对应的开发包;

class Person{
}
public class MAIN {
    public static void main(String[] args) {
        Class<?> cls = Person.class;
        System.out.println(cls.getName());  // 获取的是类的完整名称
    }
}
 

 

 

【Class类支持】:在Class类中有一个static方法:

  - 采用的是字符串的形式定义要使用的类型,并且程序中不需要编写任何的import语句;

public static Class<?> forName​(String className) throws ClassNotFoundException;
package Demo_2_27_反射1_Person
package Demo_2_27_反射1
public class Person {
}

public class MAIN {
    public static void main(String[] args) throws Exception{
        Class<?> cls = Class.forName("Demo_2_27_反射1_Person.Person");
        System.out.println(cls.getName());  // 获取的是类的完整名称
    }
}

如果此时要使用的程序类不存在,那么会出现“ClassNotFoundException”的异常。

 

 

反射实例化对象:

获取了Class对象的最大意义实际上并不是在于只是对象的实例化操作形式,更重要的是Clss类里面提供有一个对象的实例化方法(代替了关键字new):

  - 在JDK1.9之前的实例化:

@Deprecated(since="9") public T newInstance() throws InstantiationException, IllegalAccessException;

  - 在JDK1.9之后:

clazz.getDeclaredConstructor().newInstance();

通过newInstance()方法实例化Person类对象:


package Demo_2_27_反射1_Person
package Demo_2_27_反射1
public class Person {
    // 任何情况下实例化对象都要调用类的构造方法
    public Person() {
        System.out.println("******* Person类构造方法 **********");
    }

    @Override
    public String toString() {
        return "我是Person类!";
    }
}

 

public class MAIN {
    public static void main(String[] args) throws Exception{
        Class<?> cls = Class.forName("Demo_2_27_反射1_Person.Person");
        Object obj = cls.newInstance();// 实例化对象,JDK1.9之后被废除
        System.out.println(obj);    // 输出对象调用toString()方法
    }
}

输出结果:

【cls.newInstance()等价于关键字new】:******* Person类构造方法 **********

【System.out.println(obj);】:我是Person类!

 

使用newInstance()方法依然要调用类的无参构造方法,其本质等价于“类 对象 = new 类()”,相当于隐含了关键字new,而直接使用字符串进行替代。

 

JDK1.9之后newInstance()被替代了:

public class MAIN {
    public static void main(String[] args) throws Exception{
        Class<?> cls = Class.forName("Demo_2_27_反射1_Person.Person");
        Object obj = cls.getDeclaredConstructor().newInstance();
        System.out.println(obj);    // 输出对象调用toString()方法
    }
}

因为默认的Class类中的newInstance()方法只能够调用无参构造,被认为描述不正确,所以将其变换了形式。

 

 反射与工厂设计模式:

静态工厂类:

工厂模式是避免客户端直接与类进行交集,通过返回接口的方式进行安全使用;

interface IMessage {
    public void send();
}

class NetMessage implements IMessage {
    @Override
    public void send() {
        System.out.println("发送网络消息!!");
    }
}

class Factory {
    private Factory() {
    } // 工厂类不需要进行实例化,所以进行构造方法私有化

    public static IMessage getInstance(String className) {   // 因为不会实例化,所以方法都使用static修饰,方便调用
        if ("NetMessage".equals(className)) {    // 传入的类名称判断
            return new NetMessage();
        }
        return null;
    }
}

public class MAIN {
    public static void main(String[] args) {
        IMessage msg = Factory.getInstance("NetMessage");
        assert msg != null;
        msg.send();
    }
}

 

以上的工厂设计模式属于静态工厂模式,最大的缺点就是,当需要追加一个接口的子类的时候,那么工厂类必须进行修改。

如果现在再追加一个子类class CloudMessage:

 

class CloudMessage implements IMessage{
    @Override
    public void send() {
        System.out.println("云消息!!");
    }
}

 

动态工厂类:

那么现在的工厂类中的判断就必须进行修改:

 

class Factory {
    private Factory() {
    } // 工厂类不需要进行实例化,所以进行构造方法私有化

    public static IMessage getInstance(String className) {   // 因为不会实例化,所以方法都使用static修饰,方便调用
        if ("NetMessage".equals(className)) {    // 传入的类名称判断
            return new NetMessage();
        }else if ("CloudMessage".equals(className)){
            return new CloudMessage();
        }
        return null;
    }
}

 

如果不增加一个对CloudMessage的判断对象获取,那么将无法获取CloudMessage的实例化对象。

随着接口的使用,可能就会产生越来越多的子类,那么这样的修改是会让人无法接受的,所以就需要进行改进为另一种方式。

这种时候最好的解决方案就是不适用关键字new来完成,因为关键字new的使用需要一个明确的类存在。而newInstance()的方法只需要一个表示类名称的字符串即可应用。

现在对工厂类进行修改:

 

package Demo_2_27_反射与工厂设计模式;

interface IMessage {
    public void send();
}

class NetMessage implements IMessage {
    @Override
    public void send() {
        System.out.println("发送网络消息!!");
    }
}
class CloudMessage implements IMessage{
    @Override
    public void send() {
        System.out.println("云消息!!");
    }
}
class Factory {
    private Factory() {
    } // 工厂类不需要进行实例化,所以进行构造方法私有化

    public static IMessage getInstance(String className) {   // 因为不会实例化,所以方法都使用static修饰,方便调用
        IMessage instance = null;
        try {
            instance = (IMessage) Class.forName(className).getDeclaredConstructor().newInstance();  // 使用反射机制获取子类对象
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }
}

public class MAIN {
    public static void main(String[] args) {
        IMessage msg = Factory.getInstance("Demo_2_27_反射与工厂设计模式.CloudMessage");
        assert msg != null;
        msg.send();
    }
}

 

此时再进行子类对象的追加的时候,工厂类都不会进行任何的修改。

静态和动态都是通过名称寻找,不同的是静态需要先确保子类存在并能通过识别判断,而动态则只需要确保子类存在即可,因为反射的机制会自动去寻找存在的子类并创建实例化对象。

思考(多接口的工厂模式):

此时的工厂类已经看似完善,但是在实际情况中,存在大量的接口,并且这些接口都可能通过工厂类进行实例化,所以工厂类不应该只是为某一个类进行服务,而是应该为所有的接口进行服务。

此时工厂类就需要再进行接口的泛型化:

interface IMessage {
    public void send();
}
interface IService{
    public void service();
}
class HouseService implements IService {
    @Override
    public void service() {
        System.out.println("【住宿服务】");
    }
}

class NetMessage implements IMessage {
    @Override
    public void send() {
        System.out.println("【发送网络消息】");
    }
}
class CloudMessage implements IMessage{
    @Override
    public void send() {
        System.out.println("【云消息】");
    }
}
class Factory {
    private Factory() {
    } // 工厂类不需要进行实例化,所以进行构造方法私有化

    @SuppressWarnings("unchecked")  // 强制转型的时候会有警告,进行压制即可
    public static <T> T getInstance(String className,Class<T> cls) {    // 传入的参数1:接口的子类,包.类名称;传入的参数2:接口的类型
        T instance = null;
        try {
            instance = (T) Class.forName(className).getDeclaredConstructor().newInstance();  // 使用反射机制获取子类对象
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }
}

public class MAIN {
    public static void main(String[] args) {
        IMessage msg = Factory.getInstance("Demo_2_27_反射与工厂设计模式.CloudMessage",IMessage.class);
        msg.send();
        IService sv = Factory.getInstance("Demo_2_27_反射与工厂设计模式.HouseService",IService.class);
        sv.service();
    }
}

 此时的工厂类不再受限于子类和接口追加。

 

 反射与单例设计模式:

仅针对懒汉式(对象的创建需要调用方法):

下面进行以前的单例创建,可以发现在多线程的情况下,每个线程都会进行实例化,所以这种思路是错误的。

package Demo_2_27_反射与单例设计;
class Singleton {   // 懒汉式
    private static Singleton instance = null;
    private Singleton(){
        System.out.println("【线程 - " + Thread.currentThread().getName() + " 】 ******* 懒汉式对象实例化 ********");
    }
    public static Singleton getInstance(){
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }
    public void print(){
        System.out.println("懒汉式!!");
    }
}
public class MAIN {
    public static void main(String [] args){
        for (int i = 0; i < 3; i++) {
            new Thread(()->{
                Singleton.getInstance().print();
            },"线程" + (i+1)).start();
        }
    }
}

单例模式最大的特点是:在运行过程之中只允许产生一个实例化对象。

而上面的结果明显不能表示单例设计模式。

那么问题出现在哪一步呢?

逆序推导可以发现,单例设计要求的是只能有一个实例化对象,但是每个线程都实例化了一个对象,那么问题多半就出现在了实例化对象的步骤,而实例化对象的步骤在程序中的方法中,那么就需要对这个方法进行改进。

首先程序的运行,多个线程同时进入到getInstance()方法,这个时候就能很明显地发现问题了,因为此时instance并没有实例化,每个线程在这里的if()判断的结果都是为空,显然此时并不能让线程同时访问这个方法,那么就需要线程同步处理以达到线程的先后访问。

那么怎么进行同步处理呢?

首先想到的应该是对方法加上synchronized关键字:

public static synchronized Singleton getInstance(){
        if (instance == null){
            instance = new Singleton();
        }
        return instance;
    }

现在getInstance()方法明显是同步了,但是问题同样出现,当多个线程(30个)进行访问的时候,在第一个线程访问的时候,其余的29个都必须等待第一个访问完成才能访问,极大地降低了性能,这个时候同步处理的地方只有if()判断需要.

更加合理地加上同步:

class Singleton {   // 懒汉式
    private static volatile Singleton instance = null;
    private Singleton(){
        System.out.println("【线程 - " + Thread.currentThread().getName() + " 】 ******* 懒汉式对象实例化 ********");
    }
    public static Singleton getInstance(){
        if (instance == null) {     // 对象为空判断,只有第一个访问的线程为空,创建后其余线程访问就不是空了
            synchronized(Singleton.class){  // synchronized作用于一个类synchronized(类名.class)
                if (instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
    public void print(){
        System.out.println("【线程 - " + Thread.currentThread().getName() + " 】" + "懒汉式!!");
    }
}
public class MAIN {
    public static void main(String [] args){
        for (int i = 0; i < 3; i++) {
            new Thread(()->{
                Singleton.getInstance().print();
            },"线程" + (i+1)).start();
        }
    }
}

此时就是单例模式了。

 

面试题:请编写单例设计模式?

  - 【100%】直接编写一个饿汉式(一开始就创建好了对象)单例设计,并且实现构造方法私有化;

class Single{
    private Single(){
    }
    private static final Single s=new Single();
    public static Single getInstance(){
        return s;
    }
}               

 

  - 【120%】在java中哪里用到了单例设计模式?

      - Runtime类、Spring框架;

  - 【200%】懒汉式单例设计模式的问题?

      - 当多线程访问时,存在安全隐患;

      - 【解决方法】:在对象创建时加上同步(因为静态方法是随类的加载而加载,优先于对象,所以使用的锁是类的字节码文件Singleton.class);

 

 

 

反射与类:

类的定义一般存在包、父类、父接口等;

获取类结构信息:

package Demo_2_28_反射获取类结构信息;

interface IChanelServ{
    public boolean connect();
}
interface IServ{
    public void send();
}
abstract class Base{
}
class Person extends Base implements IServ,IChanelServ{
    @Override
    public boolean connect() {
        return true;
    }

    @Override
    public void send() {
        System.out.println("【发送Message!】");
    }
}
public class MAIN {
    public static void main(String[] args) {
        Class<?> csc = Person.class;    // 获取指定类的Class对象
        System.out.println("Class对象.getPackage() - 获取包定义(返回值类型为Package 格式为 Package 包名):" + csc.getPackage());
        System.out.println("Class对象.getPackageName() - 获取包名称(返回值类型为String 格式为 包名):" + csc.getPackageName());
        System.out.println("Class对象.getPackage().getName() - 获取包名称(返回值类型为String 格式为 包名):" + csc.getPackage().getName());
        System.out.println("Class对象.getSuperclass() - 获取父类信息(返回值类型为Class<?superT> 格式为 class 包名.父类名称):" + csc.getSuperclass());
        System.out.println("Class对象.getSuperclass().getName() - 获取父类名称(返回值类型为Class<?superT> 格式为 包名.父类名称):" + csc.getSuperclass().getName());
        Class<?>[] cscs = csc.getInterfaces();
        for (Class<?> css : cscs) {
            System.out.println("Class对象.getInterfaces() - 获取父接口信息(返回值类型为Class<?>[] 格式为 interface 包名.父接口名):" + css);
            System.out.println("Class对象.getInterfaces() - 获取父接口名称(返回值类型为String 格式为 包名.父接口名):" + css.getName());
        }
        System.out.println("Class对象.getName() - 获取类信息(返回值类型为String 格式为 包名.类名):" + csc.getName());

    }
}

 输出结果:

Class对象.getPackage() - 获取包定义(返回值类型为Package 格式为 Package 包名):package Demo_2_28_反射获取类结构信息
Class对象.getPackageName()
- 获取包名称(返回值类型为String 格式为 包名):Demo_2_28_反射获取类结构信息
Class对象.getPackage().getName()
- 获取包名称(返回值类型为String 格式为 包名):Demo_2_28_反射获取类结构信息
Class对象.getSuperclass()
- 获取父类信息(返回值类型为Class<?superT> 格式为 class 包名.父类名称):class Demo_2_28_反射获取类结构信息.Base
Class对象.getSuperclass().getName()
- 获取父类名称(返回值类型为Class<?superT> 格式为 包名.父类名称):Demo_2_28_反射获取类结构信息.Base
Class对象.getInterfaces()
- 获取父接口信息(返回值类型为Class<?>[] 格式为 interface 包名.父接口名):interface Demo_2_28_反射获取类结构信息.IServ
Class对象.getInterfaces().getName()
- 获取父接口名称(返回值类型为String 格式为 包名.父接口名):Demo_2_28_反射获取类结构信息.IServ
Class对象.getInterfaces()
- 获取父接口信息(返回值类型为Class<?>[] 格式为 interface 包名.父接口名):interface Demo_2_28_反射获取类结构信息.IChanelServ
Class对象.getInterfaces().getName()
- 获取父接口名称(返回值类型为String 格式为 包名.父接口名):Demo_2_28_反射获取类结构信息.IChanelServ
Class对象.getName()
- 获取类信息(返回值类型为String 格式为 包名.类名):Demo_2_28_反射获取类结构信息.Person

 从上面的步骤我们可以得到:

  当我们获取了一个类的Class文件的时候,就可以获取这个类的所有继承结构信息,包括 所属包、父类、父接口等;

 

 

 Class对象获取类的构造方法:

 通过Class类中的方法来获取类的构造方法,首先需要一个类.class的Class对象,然后通过方法来获取构造:

import java.lang.reflect.Constructor;

interface IChanelServ {
    public boolean connect();
}

interface IServ {
    public void send();
}

abstract class Base {
    public Base() {
    }
}

class Person extends Base implements IServ, IChanelServ {
    private String name;
    int age;
    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "name='" + name + '\'' +
                ", age=" + age + "\t";
    }

    @Override
    public boolean connect() {
        return true;
    }

    @Override
    public void send() {
        System.out.println("【发送Message!】");
    }
}

public class MAIN {
    public static void main(String[] args) throws Exception {
        Class<?> per = Person.class;    // 获取指定类的Class对象
        for (Constructor<?> constructor : per.getDeclaredConstructors()) {  // 获取本类构造
            System.out.println("类的Class对象.getDeclaredConstructor() - 获取全部构造(返回值类型为 Constructor<?>[] 格式为 权限控制符 包名.构造方法名(空 | 参数类型1,参数类型2,参数类型3...)):" + constructor);
        }
        for (Constructor<?> constructor : per.getConstructors()) {  // 获取父子类构造
            System.out.println("类的Class对象.getConstructor() - 获取全部构造(返回值类型为 Constructor<?>[] 格式为 权限控制符 包名.构造方法名(空 | 参数类型1,参数类型2,参数类型3...)):" + constructor);
        }
        Constructor<?> constructor = per.getConstructor(String.class,int.class);    // 获取有参构造并传入对应参数类型.class
        Object obj = constructor.newInstance("张三",12);  // 实例化对象
        System.out.println(obj);    // 输出对象toString()
    }
}
类的Class对象.getDeclaredConstructor() - 获取全部构造(返回值类型为 Constructor<?>[] 格式为 权限控制符 包名.无参构造方法名(空)):public Demo_2_28_Class获取类构造方法.Person()
类的Class对象.getDeclaredConstructor()
- 获取全部构造(返回值类型为 Constructor<?>[] 格式为 权限控制符 包名.有参构造方法名(空 | 参数类型1,参数类型2,参数类型3...)):public Demo_2_28_Class获取类构造方法.Person(java.lang.String,int)
类的Class对象.getConstructor()
- 获取全部构造(返回值类型为 Constructor<?>[] 格式为 权限控制符 包名.无参构造方法名(空)):public Demo_2_28_Class获取类构造方法.Person()
类的Class对象.getConstructor()
- 获取全部构造(返回值类型为 Constructor<?>[] 格式为 权限控制符 包名.有参构造方法名(空 | 参数类型1,参数类型2,参数类型3...)):public Demo_2_28_Class获取类构造方法.Person(java.lang.String,int)
name
='张三', age=12

虽然程序代码允许开发者调用有参构造处理,但是所有使用反射的类中最好拥有无参构造,因为这样的实例化可以达到统一性。

 

 

 反射调用普通方法:

已知可以利用反射获取类中的普通方法,但是在调用这些普通方法的时候需要有一个前提条件:类之中提供有实例化的对象;

 获取方法:

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

interface IChanelServ {
    public boolean connect();
}

interface IServ {
    public void send();
}

abstract class Base {
    public Base() {
    }
}

class Person extends Base implements IServ, IChanelServ {
    private String name;
    int age;
    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "name='" + name + '\'' +
                ", age=" + age + "\t";
    }

    @Override
    public boolean connect() {
        return true;
    }

    @Override
    public void send() {
        System.out.println("【发送Message!】");
    }
}

public class MAIN {
    public static void main(String[] args) throws Exception {
        Class<?> per = Person.class;    // 获取指定类的Class对象
        {// 获取全部方法(包括父类中的方法)
            for (Method method : per.getMethods()) {
                System.out.println("类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):" + method);
            }
        }
        System.out.println("\n************************************************************************************************************************************************************************************\n");
        {// 获取本类方法
            for (Method method : per.getDeclaredMethods()) {
                System.out.println("类Class对象.getDeclaredMethods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...)):" + method);
            }
        }
    }
}

输出结果:

类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):public java.lang.String Demo_2_28_Class获取类普通方法.Person.toString()
类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):public boolean Demo_2_28_Class获取类普通方法.Person.connect()
类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):public void Demo_2_28_Class获取类普通方法.Person.send()
类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):public final void java.lang.Object.wait() throws java.lang.InterruptedException
类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):public boolean java.lang.Object.equals(java.lang.Object)
类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):public native int java.lang.Object.hashCode()
类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):public final native java.lang.Class java.lang.Object.getClass()
类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):public final native void java.lang.Object.notify()
类Class对象.methods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...) 抛出的异常):public final native void java.lang.Object.notifyAll()

************************************************************************************************************************************************************************************

类Class对象.getDeclaredMethods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...)):public java.lang.String Demo_2_28_Class获取类普通方法.Person.toString()
类Class对象.getDeclaredMethods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...)):public boolean Demo_2_28_Class获取类普通方法.Person.connect()
类Class对象.getDeclaredMethods() - 获取全部类方法(返回值类型: Method[] 格式: 格式控制符 包名.类名.方法名(参数类型1,参数类型2...)):public void Demo_2_28_Class获取类普通方法.Person.send()

通过反射机制来实现Person类中的setter()和getter()方法处理:

Method类中最重要的方法就是invoke()方法:

invoke()方法就相当于一个中间传递者;

Method-c.invoke(Object-a,对应类型的参数-b) :Object-a调用Object-a中的Method-c()方法传入参数为参数类型-b,如果Object-a中的Method-c()方法没有传入参数,那么形式为Method-c.invoke(Object-a);

其中Method-c是Method类型,对应类型的参数-b的类型在Method-c获取的时候就定义了。

public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException,InvocationTargetException

 

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

interface IChanelServ {
    public boolean connect();
}

interface IServ {
    public void send();
}

abstract class Base {
    public Base() {
    }
}

class Person extends Base implements IServ, IChanelServ {
    private String name;
    int age;
    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "name='" + name + '\'' +
                ", age=" + age + "\t";
    }

    @Override
    public boolean connect() {
        return true;
    }

    @Override
    public void send() {
        System.out.println("【发送Message!】");
    }
}

public class MAIN {
    public static void main(String[] args) throws Exception {
        Class<?> per = Class.forName("Demo_2_28_Class获取类普通方法.Person");    // 不导入包,获取指定类的Class对象
        String attribute = "name";  // 要操作的类属性
        String value = "zhangsan";   // 要设置的内容
        // 1.任何情况下如果想要保存类中的属性或调用类中的方法都必须保证存在有实例化对象,不导入包则进行反射实例化
        Object obj = per.getDeclaredConstructor().newInstance();    // 调用无参构造实例化
        // 2. 如果要想进行方法的调用,那么一定要获取方法名称
        String setMethodName = "setName";   // 方法名称
        Method setMethod = per.getDeclaredMethod(setMethodName,String.class); // 获取指定的方法
        setMethod.invoke(obj,value);   // 等价于Person类.setName(value)
        String getMethodName = "getName";   // 方法名称
        Method getMethod = per.getDeclaredMethod(getMethodName); // 获取指定的方法
        System.out.println(getMethod.invoke(obj));   // 等价于Person类.getName()
    }
}

输出结果:

使用这种操作全部使用反射机制处理,没有任何一个具体的类对象产生,避免了类的耦合。

 

 反射与获取成员属性:

 通过Field类中的方法可以获取一个类中的成员属性:

(提示:在获取父类中成员的时候,如果没有成功获取可能是因为成员属性被private修饰)

import java.lang.reflect.Field;

interface IChanelServ{

    static final String NAME = "www.baidu.com/ICS";
    String url = "http://";
    public boolean connect();
}

interface IServ{
    static final String NAME = "www.baidu.com/IS";
    String url = "http://";
    public void send();
}

abstract class Base{
    private static final String NAME = "www.baidu.com/Base";
    private String url = "http://";
}

class Person extends Base implements IChanelServ,IServ{
    private static final String NAME = "www.baidu.com/Person";
    private static final String URL = "http://";
    @Override
    public boolean connect() {
        return true;
    }

    @Override
    public void send() {
        System.out.println("【发送Message!】");
    }
}

public class MAIN {
    public static void main(String[] args) throws Exception{
        Class<?> csc = Class.forName("Demo_3_1_Class获取类成员属性.Person");    // 获取指定类的Class对象
        System.out.println("\n*********** 获取父类全部成员 ***********");
        for (Field field : csc.getFields()) {
            System.out.println("类Class对象.getFields() - 获取父类(或父接口)的全部公共成员属性(返回值类型:Field[]):" + field);
        }
        System.out.println("\n*********** 获取父类指定成员 ***********");
        System.out.println("类Class对象.getField(String name) - 获取父类(或父接口)的指定公共成员属性(返回值类型:Field):" + csc.getField("NAME"));
        System.out.println("类Class对象.getField(String name):获取的是第一个存在此属性的接口,如果这个接口没有此属性则向后寻找到第一个有此属性的接口,然后返回");
        System.out.println("\n*********** 获取本类全部成员 ***********");
        for (Field field : csc.getDeclaredFields()) {
            System.out.println("类Class对象.getDeclaredFields() - 获取本类的全部成员属性(返回值类型:Filed[])" + field);
        }
        System.out.println("\n*********** 获取本类指定成员 ***********");
        System.out.println("类Class对象.csc.getDeclaredField(String name) - 获取本类的指定成员属性(返回值类型:Filed)" + csc.getDeclaredField("NAME"));

    }
}

输出结果:

*********** 获取父类全部成员 ***********
类Class对象.getFields() - 获取父类(或父接口)的全部公共成员属性(返回值类型:Field[]):public static final java.lang.String Demo_3_1_Class获取类成员属性.IChanelServ.NAME
类Class对象.getFields() - 获取父类(或父接口)的全部公共成员属性(返回值类型:Field[]):public static final java.lang.String Demo_3_1_Class获取类成员属性.IChanelServ.url
类Class对象.getFields() - 获取父类(或父接口)的全部公共成员属性(返回值类型:Field[]):public static final java.lang.String Demo_3_1_Class获取类成员属性.IServ.NAME
类Class对象.getFields() - 获取父类(或父接口)的全部公共成员属性(返回值类型:Field[]):public static final java.lang.String Demo_3_1_Class获取类成员属性.IServ.url

*********** 获取父类指定成员 ***********
类Class对象.getField(String name) - 获取父类(或父接口)的指定公共成员属性(返回值类型:Field):public static final java.lang.String Demo_3_1_Class获取类成员属性.IChanelServ.NAME
类Class对象.getField(String name):获取的是第一个存在此属性的接口,如果这个接口没有此属性则向后寻找到第一个有此属性的接口,然后返回

*********** 获取本类全部成员 ***********
类Class对象.getDeclaredFields() - 获取本类的全部成员属性(返回值类型:Filed[])private static final java.lang.String Demo_3_1_Class获取类成员属性.Person.NAME
类Class对象.getDeclaredFields() - 获取本类的全部成员属性(返回值类型:Filed[])private static final java.lang.String Demo_3_1_Class获取类成员属性.Person.URL

*********** 获取本类指定成员 ***********
类Class对象.csc.getDeclaredField(String name) - 获取本类的指定成员属性(返回值类型:Filed)private static final java.lang.String Demo_3_1_Class获取类成员属性.Person.NAME

 

所有的对象都是在实例化之后才进行空间分配,所以此时一定要先有实例化对象之后才可以进行成员的操作;

import java.lang.reflect.Field;

interface IChanelServ{

    static final String NAME = "www.baidu.com/ICS";
    String url = "http://";
    public boolean connect();
}

interface IServ{
    static final String NAME = "www.baidu.com/IS";
    String url = "http://";
    public void send();
}

abstract class Base{
    private static final String NAME = "www.baidu.com/Base";
    private String url = "http://";
}

class Person extends Base implements IChanelServ,IServ{
    private static final String NAME = "www.baidu.com/Person";
    private String url;
    private int age;
    @Override
    public boolean connect() {
        return true;
    }

    @Override
    public void send() {
        System.out.println("【发送Message!】");
    }
}

public class MAIN {
    public static void main(String[] args) throws Exception{
        Class<?> csc = Class.forName("Demo_3_1_Class获取类成员属性.Person");    // 获取指定类的Class对象
        System.out.println("\n*********** Field中的set和get方法设置成员属性 ***********");
        Object obj = csc.getDeclaredConstructor().newInstance();    // 实例化对象后才会分配空间,才能使用其中的成员属性
        Field field = csc.getDeclaredField("url");      // 获得指定成员属性
        field.setAccessible(true);  // 解除封装 ==> 解除private的限制
        field.set(obj,"http://");   // 设置成员属性的值 ==> Person.url = "http://"
        // 注意:此时url的权限为private,所以无法从外部获取url的值,所以需要先进行封装的解除
        System.out.println(field.get(obj)); //  获取成员属性的值 ==> Person.url
    }
}

输出结果:

*********** Field中的set和get方法设置成员属性 ***********
http:// 

 以上过程只是对反射机制的了解,在实际应用中,成员属性的设置都是通过setter或getter进行,最好是不要随意地去打破封装,因为会造成安全隐患。

Field类中在实际应用中只有一个方法最为常用:

- 获取成员类型:public Class<?>getType();
System.out.println(field.getType().getName());  // 获取包名加类名
System.out.println(field.getType().getSimpleName());    // 获取类名

输出结果:

java.lang.String
String

结合前面的Method类可以发现,通过Method类进行方法的获取,然后通过Field类的set()方法进行设置属性值,就实现了类中的setter()方法.

 

 

传统属性赋值弊端:

在设置属性的数据值的时候,一般都是通过setter()方法进行设置,在属性数量较少的情况下还能够接受,但是当数量有几十个甚至上百个的时候,就需要一大堆的setter()和getter()方法,甚至一个类是这样,而实际情况中这种类一般都存在很多个,并且值的设置可能还存在重复性,那么这种情况让人一想到就头大,所以需要改进一下,利用反射机制来简化大量的重复操作。

属性的自动设置

类中的属性名和值都使用String字符串的形式进行定义,并用 | 隔开方便分割,然后所有的反射处理与内容设置都在一个专门的ClassInstanceFactory类中进行。

 基本结构:

class ClassInstanceFactory{
    private ClassInstanceFactory(){}

    /**
     * 实例化对象的操作,该对象可以根据传入的字符串"属性:内容|属性:内容|属性:内容|。。。"对属性的值进行设置
     * @param classes 进行反射实例化的Class对象,传入了Class类对象就可以进行反射实例化
     * @param value 设置实例化对象的属性的值
     * @param <T> 返回值的类型
     * @return 返回设置后的对象
     */
    public static <T> T create(Class<?> classes,String value){
        return null;
    }
}
class Emp{
    private String ename;
    private String job;

    public Emp() {
    }

    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;
    }
}
public class MAIN {
    public static void main(String[] args) {
        String value = "ename:smith|job:driver";
        
    }
}

此时需要做两件事情:

  - 通过反射进行指定对象的实例化处理;

  - 进行内容的设置(Field类获取属性类型、方法名称、内容的设置);

使用BeanUtils类进行数据的设置处理操作;

setter()和getter()方法需要将属性的首字母大写,那么就需要一个StringUtils类来进行处理;

代码实现:

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class Emp{
    private String ename;
    private String job;

    public Emp() {
    }

    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;
    }
}

class ClassInstanceFactory{
    private ClassInstanceFactory(){}

    /**
     * 实例化对象的操作,该对象可以根据传入的字符串"属性:内容|属性:内容|属性:内容|。。。"对属性的值进行设置
     * @param classes 进行反射实例化的Class对象,传入了Class类对象就可以进行反射实例化
     * @param value 设置实例化对象的属性的值
     * @param <T> 返回值的类型
     * @return 返回设置后的对象
     */
    public static <T> T create(Class<?> classes,String value){
        try {   // 如果想要使用反射进行简单Java类对象属性设置的时候,类中必须要有无参构造
            Object obj = classes.getDeclaredConstructor().newInstance();
            BeanUtils.setValue(obj,value);  // 通过反射设置属性
            return (T)obj;  // 返回对象
        } catch (Exception e) {
            e.printStackTrace();    // 如果出现了异常,抛出异常也没用
            return null;
        }
    }
}
class BeanUtils{    // 设置属性数据的类
    private BeanUtils(){}

    /**
     * 实现指定对象的属性设置
     * @param obj 实例化对象
     * @param value 对象需要设置的值
     */
    public static void setValue(Object obj,String value){
        String[] res = value.split("\\|");  // 按照 | 进行分组拆分
        for (int i = 0; i < res.length; i++) {  // 循环设置属性内容
            // attval[0]:属性名称、attval[1]:属性内容
            String[] attval = res[i].split(":");    // 按:分割获取属性名称和属性内容
            try {
                Field field = obj.getClass().getDeclaredField(attval[0]);// 找到类的成员属性
                Method setMethod = obj.getClass().getDeclaredMethod("set" + StringUtils.initCap(attval[0]),field.getType());    // 找到类的setter()方法
                setMethod.invoke(obj,attval[1]);    // 调用setter()方法设置内容
            }catch (Exception e){}
        }
    }
}
class StringUtils{  // 首字母大写处理类
    private StringUtils(){}
    public static String initCap(String str){
        if (str == null || "".equals(str)){ // 字符串为空
            return str;
        }
        if (str.length() == 1){     // 只有一个字母
            return str.toUpperCase();
        }else { // 一串字符串
            return str.substring(0,1).toUpperCase() + str.substring(1); // 获取字符串第一个字母并大写,然后拼接上字符串第二位至结束的字符串,例如:“hello”-->"h"->"H"-->"H"+"ello"-->"Hello"
        }
    }
}
public class MAIN {
    public static void main(String[] args) {
        String value = "ename:smith|job:driver";
        Emp emp = ClassInstanceFactory.create(Emp.class,value);
        System.out.println("姓名:" + emp.getEname() + "、职位:" + emp.getJob());
    }
}

输出结果:

 这样就通过一串字符串将Emp类中的属性进行赋值,上面是ename和job两个属性,那么就算再加上几十个一百个也没有关系,因为大量的重复操作被几个功能类进行实现,现在只需要向其中传入对应的参数就行,而属性和属性的内容就只需要用一串字符串表示就行。

 

 多级关联对象实例化:

 传入的字符串通过" . "的形式表示关联关系如:公司、部门、员工有:dept(部门). company(公司).cname(公司名称)或者 dept(部门). dname(部门名称)来表示关联关系,这样方便后面的分割,找出各个属性。

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

class Emp {
    private long empo;
    private String ename;
    private String job;
    private double salary;
    private Date hireDate;
    private Dept dept;

    public Emp() {
//        System.out.println("【无参构造】emp");
    }
    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    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;
    }

    public long getEmpo() {
        return empo;
    }

    public void setEmpo(long empo) {
        this.empo = empo;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public Date getHireDate() {
        return hireDate;
    }

    public void setHireDate(Date hireDate) {
        this.hireDate = hireDate;
    }
}

class Dept { //部门
    private String dname;
    private String loc;
    private Company company;

    public Dept() {
//        System.out.println("【无参构造】dept");
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }

    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "dname='" + dname + '\'' +
                ", loc='" + loc + '\'' +
                ", company=" + company +
                '}';
    }
}

class Company {  // 公司
    private String cname;
    private Date createDate;

    public Company() {
//        System.out.println("【无参构造】company");
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    @Override
    public String toString() {
        return "Company{" +
                "cname='" + cname + '\'' +
                ", createDate=" + createDate +
                '}';
    }
}

class createUtils {
    /**
     * 实现指定对象的属性设置
     *
     * @param obj   实例化对象
     * @param value 对象需要设置的值
     */
    public static void setValue(Object obj, String value) {
        String[] res = value.split("\\|");  // 按照 | 进行分组拆分,得到一组一组每个信息的数据,每一组有两个数据
        for (String re : res) {  // 循环设置属性内容
            // attval[0]:属性名称、attval[1]:属性内容
            String[] attval = re.split("==");    // 按:分割获取属性名称和属性内容
            try {   // 捕获异常,以保证在属性名称出错但是属性内容没错的时候程序会继续运行
                if (attval[0].contains(".")) {  // 多级配置
                    String[] result = attval[0].split("\\.");   // 将字符串以 "." 分割然后保存,结果数组中的最后一位为属性内容
                    Object currentObj = obj;    // 新建一个代替obj
                    for (int i = 0; i < result.length-1; i++) { // 循环获取名称属性,最后一位为属性内容,所以长度减一
                        Method getMethod = currentObj.getClass().getDeclaredMethod("get" + initCap(result[i]));     // 将属性首字母大写获取getter()方法
                        Object tmpObj = getMethod.invoke(currentObj);       // 调用getter()方法,为创建那么为空,需要进行下面的创建过程
                        if (tmpObj == null){    // 如果上面的getter()方法获取为空
                            Field field = currentObj.getClass().getDeclaredField(result[i]);    // 获取指定(result数组中的元素)属性
                            Method setMethod = currentObj.getClass().getDeclaredMethod("set" + initCap(result[i]),field.getType()); // 查找对应参数类型的setter()方法
                            Object newObj = field.getType().getDeclaredConstructor().newInstance();     // 新建setter()方法要返回的实例化对象
                            System.out.println("field.getType() -- " + field.getType());
                            System.out.println("newObj.getClass() -- " + newObj.getClass());
                            setMethod.invoke(currentObj,newObj);
                            System.out.println("newObj.getClass() -- " +newObj.getClass());
                            currentObj = newObj;
                            System.out.println("currentObj.getClass() -- " + currentObj.getClass());
                        }else {
                            currentObj = tmpObj;
                        }
                } else {
                    Field field = obj.getClass().getDeclaredField(attval[0]);// 找到类的成员属性
                    Method setMethod = obj.getClass().getDeclaredMethod("set" + initCap(attval[0]), field.getType());    // 找到类的setter()方法
                    Object convertVal = convertAttributeValue(field.getType().getName(), attval[1]);  // 得到属性的类型的字符串
                    setMethod.invoke(obj, convertVal);    // 调用setter()方法设置内容
                }
            } catch (Exception e) {
//                System.out.println("setValue()方法出错!");
                e.printStackTrace();
            }
        }
    }

    /**
     * 将传入的字符串转换为指定类型的值
     *
     * @param type  属性的类型,通过Field类获取
     * @param value 属性的内容,传入的都是String字符串,需要将其转换为指定类型
     * @return 转换后的数据
     */
    private static Object convertAttributeValue(String type, String value) {  // 将传入的数据类型转换为指定的数据类型
        if ("long".equals(type) | "java.lang.Long".equals(type)) {   // 数据类型为长整型判断
            return Long.parseLong(value);
        } else if ("int".equals(type) | "java.lang.int".equals(type)) {   // 数据类型为整型判断
            return Integer.parseInt(value);
        } else if ("double".equals(type) | "java.lang.double".equals(type)) { // double类型判断
            return Double.parseDouble(value);
        } else if ("java.util.Date".equals(type)) {   // 日期类型判断
            SimpleDateFormat sdf;
            if (value.matches("\\d{4}-\\d{2}-\\d{2}")) { // 日期类型
                sdf = new SimpleDateFormat("yyyy-MM-dd");   // 日期类型转换
            } else if (value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {    //带时分秒的日期
                sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            } else {
                return new Date();
            }
            try {
                return sdf.parse(value);
            } catch (ParseException e) {
                return new Date();
            }
        } else {
            return value;
        }
    }

    /**
     * @param str 传入的属性名
     * @return 首字母大写后的属性名
     */
    public static String initCap(String str) {
        if (str == null || "".equals(str)) { // 字符串为空
            return str;
        }
        if (str.length() == 1) {     // 只有一个字母
            return str.toUpperCase();
        } else { // 一串字符串
            return str.substring(0, 1).toUpperCase() + str.substring(1); // 获取字符串第一个字母并大写,然后拼接上字符串第二位至结束的字符串,例如:“hello”-->"h"->"H"-->"H"+"ello"-->"Hello"
        }
    }
}
class ClassInstanceFactory {
    private ClassInstanceFactory() {
    }

    /**
     * 实例化对象的操作,该对象可以根据传入的字符串"属性:内容|属性:内容|属性:内容|。。。"对属性的值进行设置
     *
     * @param classes 进行反射实例化的Class对象,传入了Class类对象就可以进行反射实例化
     * @param value   设置实例化对象的属性的值
     * @param <T>     返回值的类型
     * @return 返回设置后的对象
     */
    public static <T> T create(Class<?> classes, String value) {
        try {   // 如果想要使用反射进行简单Java类对象属性设置的时候,类中必须要有无参构造
            Object obj = classes.getDeclaredConstructor().newInstance();
            createUtils.setValue(obj, value);  // 通过反射设置属性
            return (T) obj;  // 返回对象
        } catch (Exception e) {
            e.printStackTrace();    // 如果出现了异常,抛出异常也没用
            return null;
        }
    }
}
public class MAIN {
    public static void main(String[] args) {
        String message = "dept.company.cname==gogo|dept.dname==write|" +
                "empo==1234|ename==smith|job==driver|salary==3421.44|hireDate==2011-11-11 11:11:11";
        Emp emp = ClassInstanceFactory.create(Emp.class,message);
        System.out.println("员工编号:" + emp.getEmpo() + "、姓名:" + emp.getEname() + "、职位:" + emp.getJob() + "、工资:" + emp.getSalary() + "、日期:" + emp.getHireDate());
        System.out.println(emp.getDept());
        System.out.println(emp.getDept().getCompany());
    }
}

输出结果:

关联类的对象实例化已经完成,那么就需要对关联类的属性进行赋值;

代码实现:

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

class Emp {
    private long empo;
    private String ename;
    private String job;
    private double salary;
    private Date hireDate;
    private Dept dept;

    public Emp() {
//        System.out.println("【无参构造】emp");
    }
    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    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;
    }

    public long getEmpo() {
        return empo;
    }

    public void setEmpo(long empo) {
        this.empo = empo;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public Date getHireDate() {
        return hireDate;
    }

    public void setHireDate(Date hireDate) {
        this.hireDate = hireDate;
    }
}

class Dept { //部门
    private String dname;
    private String loc;
    private Company company;

    public Dept() {
//        System.out.println("【无参构造】dept");
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }

    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "dname='" + dname + '\'' +
                ", loc='" + loc +
                '}';
    }
}

class Company {  // 公司
    private String cname;
    private Date createDate;

    public Company() {
//        System.out.println("【无参构造】company");
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    @Override
    public String toString() {
        return "Company{" +
                "cname='" + cname + '\'' +
                ", createDate=" + createDate +
                '}';
    }
}

class createUtils {
    /**
     * 实现指定对象的属性设置
     *
     * @param obj   实例化对象
     * @param value 对象需要设置的值
     */
    public static void setValue(Object obj, String value) {
        String[] res = value.split("\\|");  // 按照 | 进行分组拆分,得到一组一组每个信息的数据,每一组有两个数据
        for (String re : res) {  // 循环设置属性内容
//            System.out.println("re -- " + re);
            // attval[0]:属性名称、attval[1]:属性内容
            String[] attval = re.split("==");    // 按:分割获取属性名称和属性内容
//            System.out.println(Arrays.toString(attval) + " -- a[1]" + attval[1]);
            try {   // 捕获异常,以保证在属性名称出错但是属性内容没错的时候程序会继续运行
                if (attval[0].contains(".")) {  // 多级配置
                    String[] result = attval[0].split("\\.");   // 将字符串以 "." 分割然后保存,结果数组中的最后一位为属性内容
                    Object currentObj = obj;    // 新建一个代替obj
                    for (int i = 0; i < result.length-1; i++) { // 循环获取名称属性,最后一位为属性内容,所以长度减一,以下代码正式开始关联类的实例化操作,当这个for循环结束后所有关联类的实例化对象都应该是存在的
                        Method getMethod = currentObj.getClass().getDeclaredMethod("get" + initCap(result[i]));     // 将属性首字母大写获取getter()方法
                        Object tmpObj = getMethod.invoke(currentObj);       // 调用getter()方法,为创建那么为空,需要进行下面的创建过程
                        if (tmpObj == null){    // 如果上面的getter()方法获取为空
                            Field field = currentObj.getClass().getDeclaredField(result[i]);    // 获取指定(result数组中的元素)属性
                            Method setMethod = currentObj.getClass().getDeclaredMethod("set" + initCap(result[i]),field.getType()); // 查找对应参数类型的setter()方法
                            Object newObj = field.getType().getDeclaredConstructor().newInstance();     // 新建setter()方法要返回的实例化对象
//                            System.out.println("field.getType() -- " + field.getType());
//                            System.out.println("newObj.getClass() -- " + newObj.getClass());
                            setMethod.invoke(currentObj,newObj);
//                            System.out.println("newObj.getClass() -- " + newObj.getClass());
                            currentObj = newObj;
//                            System.out.println("currentObj.getClass() -- " + currentObj.getClass());
                        }else {
                            currentObj = tmpObj;    // tmpObj是通过getter()方法获取的,那么如果已经实例化了相同的对象,就直接进行引用传递,不需要再实例化了
                        }
                    }
                    // 进行属性设置,此时的currentObj不可能能为空,并且是关联类的实例化对象
                    Field fieldName = currentObj.getClass().getDeclaredField(result[result.length-1]);    // 通过result[result.length-1]取出数组的最后一位属性内容找到对应的属性
                    Method setMethod = currentObj.getClass().getDeclaredMethod("set" + initCap(result[result.length-1]),fieldName.getType());     // 查找对应的setter()方法并传入参数类型
                    Object convertVal = convertAttributeValue(fieldName.getType().getName(), attval[1]);  // 得到属性的类型的字符串
                    setMethod.invoke(currentObj,convertVal);     // 调用当前实例化对象的setter()方法进行赋值
                } else {
                    Field field = obj.getClass().getDeclaredField(attval[0]);// 找到类的成员属性
                    Method setMethod = obj.getClass().getDeclaredMethod("set" + initCap(attval[0]), field.getType());    // 找到类的setter()方法
                    Object convertVal = convertAttributeValue(field.getType().getName(), attval[1]);  // 得到属性的类型的字符串
                    setMethod.invoke(obj, convertVal);    // 调用setter()方法设置内容
                }
            } catch (Exception e) {
//                System.out.println("setValue()方法出错!");
                e.printStackTrace();
            }
        }
    }

    /**
     * 将传入的字符串转换为指定类型的值
     *
     * @param type  属性的类型,通过Field类获取
     * @param value 属性的内容,传入的都是String字符串,需要将其转换为指定类型
     * @return 转换后的数据
     */
    private static Object convertAttributeValue(String type, String value) {  // 将传入的数据类型转换为指定的数据类型
        if ("long".equals(type) | "java.lang.Long".equals(type)) {   // 数据类型为长整型判断
            return Long.parseLong(value);
        } else if ("int".equals(type) | "java.lang.int".equals(type)) {   // 数据类型为整型判断
            return Integer.parseInt(value);
        } else if ("double".equals(type) | "java.lang.double".equals(type)) { // double类型判断
            return Double.parseDouble(value);
        } else if ("java.util.Date".equals(type)) {   // 日期类型判断
            SimpleDateFormat sdf;
            if (value.matches("\\d{4}-\\d{2}-\\d{2}")) { // 日期类型
                sdf = new SimpleDateFormat("yyyy-MM-dd");   // 日期类型转换
            } else if (value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {    //带时分秒的日期
                sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            } else {
                return new Date();
            }
            try {
                return sdf.parse(value);
            } catch (ParseException e) {
                return new Date();
            }
        } else {
            return value;
        }
    }

    /**
     * @param str 传入的属性名
     * @return 首字母大写后的属性名
     */
    public static String initCap(String str) {
        if (str == null || "".equals(str)) { // 字符串为空
            return str;
        }
        if (str.length() == 1) {     // 只有一个字母
            return str.toUpperCase();
        } else { // 一串字符串
            return str.substring(0, 1).toUpperCase() + str.substring(1); // 获取字符串第一个字母并大写,然后拼接上字符串第二位至结束的字符串,例如:“hello”-->"h"->"H"-->"H"+"ello"-->"Hello"
        }
    }
}
class ClassInstanceFactory {
    private ClassInstanceFactory() {
    }

    /**
     * 实例化对象的操作,该对象可以根据传入的字符串"属性:内容|属性:内容|属性:内容|。。。"对属性的值进行设置
     *
     * @param classes 进行反射实例化的Class对象,传入了Class类对象就可以进行反射实例化
     * @param value   设置实例化对象的属性的值
     * @param <T>     返回值的类型
     * @return 返回设置后的对象
     */
    public static <T> T create(Class<?> classes, String value) {
        try {   // 如果想要使用反射进行简单Java类对象属性设置的时候,类中必须要有无参构造
            Object obj = classes.getDeclaredConstructor().newInstance();
            createUtils.setValue(obj, value);  // 通过反射设置属性
            return (T) obj;  // 返回对象
        } catch (Exception e) {
            e.printStackTrace();    // 如果出现了异常,抛出异常也没用
            return null;
        }
    }
}
public class MAIN {
    public static void main(String[] args) {
        String message = "dept.company.cname==gogo|dept.dname==write|dept.company.createDate==2011-11-11 11:11:11|dept.loc==Writer|" +
                "empo==1234|ename==smith|job==driver|salary==3421.44|hireDate==2011-11-11 11:11:11";
        Emp emp = ClassInstanceFactory.create(Emp.class,message);
        System.out.println("员工编号:" + emp.getEmpo() + "、姓名:" + emp.getEname() + "、职位:" + emp.getJob() + "、工资:" + emp.getSalary() + "、日期:" + emp.getHireDate());
        System.out.println(emp.getDept());
        System.out.println(emp.getDept().getCompany());
    }
}

输出结果:

 

 一个简单Java类的关联类配置的简单案例就完成了。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

未完待续。。。

posted on 2022-02-27 11:17  时间完全不够用啊  阅读(229)  评论(0编辑  收藏  举报