学习Java必备的基础知识打卡12.29,要想学好必须扎实基本功(⭐建议收藏)#yyds干货盘点#

Posted java厂长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习Java必备的基础知识打卡12.29,要想学好必须扎实基本功(⭐建议收藏)#yyds干货盘点#相关的知识,希望对你有一定的参考价值。

Day35-Java之反射(一)

@[toc]

关于作者

• 作者介绍

反射机制如果只是针对普通开发者而言意义不大,一般都是作为一些系统的构架设计去使用的,包括以后学习的开源框架,那么几乎都是反射机制。

1.1 认识反射

反射指的是对象的反向处理操作,就首先观察以下“正”的操作,在默认情况下,必须先导入一个包才能产生类的实例化对象。

所谓的“反”根据对象来取得对象的来源信息,“反”的操作的本来来源就是Object的一个方法。

  • 取得class对象:public final 类<?> getClass() 该方法返回的一个Class类的对象,这个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());

    

此时通过对象的确对象的来源,就是“反”的本质。在反射的背后不在是一个对象,而是对象身后的来源。

而这个getClass()方法返回的对象是Class类对象,所以这个Class就是所有反射操作的源头,但是在讲解其真正使用之前还有一个需要先解释的问题,既然Class是所有反射操作的源头,那么这个类肯定是最为重要的,而如果要想取得这个类的实例化对象,java中定义了三种方式:

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对象
        System.out.println(cla.getName());//反着来     
    
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对象
        System.out.println(cla.getName());//反着来     
    
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对象
        System.out.println(cla.getName());//反着来     
    

在以上给出的三个方法会发现一个神奇的地方,除了第一种形式会产生Date实例化对象,而第二种和第三种没有

实例化取得对象。于是取得Class类对象有一个最直接的好处:可以直接通过反射实例化对象,在Class类中有一个方法:

  • 通过反射实例化对象:public T newInstance() throws InstantiationException IllegalAccessException
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对象
        Object o = cla.newInstance();//取得Date对象
        System.out.println(o);
    

现在可以发现,对于对象的实例化操作,除了使用关键字new之外又多了一个反射机制操作,而且这个操作要比之前使用的new复杂一些,可是有什么用呢?

对于程序的开发模式之前一直强点:尽量减少耦合,而减少耦合的最好的做法是使用接口,但是就算使用了接口也逃不出关键字new,多以实际上new是耦合的关键元凶。

1.2 取得父类信息

反射可以做出一个对象所具备的所有操作行为,而且最关键的是这一切的操作都可以基于Object类型进行。

在Java里面任何的程序类实际上都一定会有一个父类,在Class类里面就可以通过此类方式来取得父类或者是实现的父接口,有如下两个方法提供:

public 软件包 getPackage() 取得类的包名称
public 类<? super T> getSuperclass() 取得父类的Class对象
public 类<?>[] getInterfaces() 取得父接口
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));
    

通过我们反射可以取得类结构上的所有关键信息。

1.3 反射调用构造

一个类可以存在多个构造方法,如果我们要想取得类中构造的调用,我们就可以使用Class类提供的两个方法

public Constructor<T> getConstructor(类<?>... parameterTypes)<br/> throws NoSuchMethodException,<br/>SecurityException 取得指定参数类型的构造方法
public Constructor<?>[] getConstructors()<br/>throws SecurityException 取得类中的所有构造

以上两个方法的返回类型都是java.lang.reflect.Constructor类的实例化对象,这个类里面关注一个方法,实例化对象:public T newInstance(Object... initargs) throws InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException

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()方法就比较麻烦

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();
        
    

学习Constructor类目的并不是分析方法的组成,最需要的关注就是问题的结论:在定义简单的java类一定要保留一个无参构造。

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对象
        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

此时运行的时候出现了错误提示“java.lang.InstancetiationException”因为以上的方式使用反射实例化对象时需要的是类之中提供无参构造方法,但是现在既然没有了无参构造方法,那么就必须明确的找到一个构造方法。

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对象
        //现在明确表示取得指定参数类型的构造方法对象
        Constructor<?> cont = cls.getConstructor(String.class,int.class);
        System.out.println(cont.newInstance("张三",19));

    

一行些简单Java类要写无参构造,以上内容就只需要了解就可以了。

1.4 反射调用方法

当取得了一个类之中的实例化对象之后,下面最需要调用的肯定是类之中的方法,所以可以继续使用Class类取得一个类中所定义的方法定义:

**public Method[] getMethods()<br/> throws SecurityException 取得全部方法
public Method getMethod(String name,Class<?>... parameterTypes)<br/> throws NoSuchMethodException, SecurityException 取得指定方法

发现以上的方法返回的都是java.lang.Method类的对象。

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类对象最大的作用不在于方法的列出(方法的列出都在开发工具上使用了),但是对于取得了Method类对象之后还有一个最大的功能,就是可以利用反射调用类的方法:
调用方法:public Object invoke(Object obj,Object... args) throws IllegalAccessException,IllegalArgumentException,InvocationTargetException
之前调用类中的方法的时候使用的都是“对象.方法”,但是现在有了反射之后,可以直接利用Object类调用指定子类的操作方法。(同事解释一下,为什么setter,和getter方法的命名要求如此严格)。

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();//实例化对象
        Method met [] = cls.getMethods();
        Method setM=cls.getMethod("setName",String.class);//通过反射构建方法
        Method getM=cls.getMethod("getName");
        setM.invoke(obj, "小张同学");//键值对的形式传递参数此过程相当于setM
        Object result = getM.invoke(obj);
        System.out.println(result);     
    

在日后所有的技术开发中,简单Java类都是如此应用,多以必须按照标准进行。

以上是关于学习Java必备的基础知识打卡12.29,要想学好必须扎实基本功(⭐建议收藏)#yyds干货盘点#的主要内容,如果未能解决你的问题,请参考以下文章

学习Java必备的基础知识打卡12.27,要想学好必须扎实基本功(⭐建议收藏)#yyds干货盘点#

学习Java必备的基础知识打卡12.16,要想学好必须扎实基本功(⭐建议收藏)#yyds干货盘点#

学习Java必备的基础知识打卡12.19,要想学好必须扎实基本功(⭐建议收藏)#yyds干货盘点#

学习Java必备的基础知识打卡12.22,要想学好必须扎实基本功(⭐建议收藏)#yyds干货盘点#

学习Java必备的基础知识打卡12.23,要想学好必须扎实基本功(⭐建议收藏)#yyds干货盘点#

学习Java必备的基础知识打卡12.7,要想学好必须扎实基本功(⭐建议收藏)#yyds干货盘点#