IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java 基础知识点 笔记总结 (十 一) -> 正文阅读

[Java知识库]Java 基础知识点 笔记总结 (十 一)

1. 反射机制


什么是动态语言,什么是静态语言?

在这里插入图片描述


Reflection(反射),java因为有了反射机制,才让java有了一定的动态性。

在这里插入图片描述

正常我们创建的方式是:

引入需要的包类名称 ==》 new实例化 ==》取得实例化对象。

而反射方式恰恰相反:

通过实例化对象 ==》 调用getClass()方法 ==》 得到完整的包类名称。

上面的过程就像光的反射一样


反射的应用场景:
在这里插入图片描述

2. 创建Person类以及其他的一些注解接口等 (方便后面测试其他方法使用)


创建了一个公共的Person类,这个类也是往后测试用的类:

package exam.demo;

@MyAnnotation(value = "hi")
public class Person extends Creature<String> implements Comparable<String> , MyInterface{

    private String name;
    int age;
    public int id;

    public Person(){}

    @MyAnnotation(value = "abc")
    public Person(String name){
        this.name = name;
    }

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

    @MyAnnotation
    private String show(String nation){
        System.out.println("我的国际是:"+nation);
        return nation;
    }

    public String display(String interests) throws Exception,NullPointerException{
        return interests;
    }

    @Override
    public void info() {
        System.out.println("我是一个人");
    }

    @Override
    public int compareTo(String o) {
        return 0;
    }

    private static void showDesc(){
        System.out.println("hello ,world.");
    }

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

Creature类:

package exam.demo;

import java.io.Serializable;

public class Creature<T> implements Serializable {
    private char gender;
    public double weight;

    private void breath(){
        System.out.println("生物呼吸");
    }

    public void eat(){
        System.out.println("生物吃东西");
    }
}

MyAnnotation注解:

package exam.demo;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME) //注解必须用RUNTIME的生命周期
public @interface MyAnnotation {

    String value() default "hello";

}

MyInterface接口:

package exam.demo;
public interface MyInterface {
    void info();
}

整体上一个反射效果案例(了解,看后面):

package filefanxingTest;

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

import org.junit.Test;

public class ReflectionTest {

	// 反射之前对于Person类的操作
	@Test
	public void test1() {
		// 1.创建Person类的对象
		Person p1 = new Person("Tom", 12);
		// 2.通过对象,调用其内部的属性,方法
		p1.age = 10;
		System.out.println(p1.toString());
		p1.show();
		// 在Person外部,不可以通过Person类的对象调用其内部私有结构
		// 比如,我们定义的name,showNation()方法以及私有的构造器。
	}

	// 反射之后,对于Person的操作
	@Test
	public void test2() throws Exception {

		// 1.通过反射创建Person类的对象
		Class clazz = Person.class;
		Constructor cons = clazz.getConstructor(String.class, int.class);
		Object obj = cons.newInstance("Tom", 12);
		Person p = (Person) obj;
		System.out.println(p.toString());

		// 2.通过反射 ,调用对象指定的属性和方法
		Field age = clazz.getDeclaredField("age");
		age.set(p, 10);
		System.out.println(p.toString());

		Method show = clazz.getDeclaredMethod("show");
		show.invoke(p);

		System.out.println("*******************");

		// 通过反射,是可以调用Person类的私有结构的,比如:私有的构造器,私有的方法,私有的属性。
		Constructor cons2 = clazz.getDeclaredConstructor(String.class);
		cons2.setAccessible(true);
		Person p2 = (Person) cons2.newInstance("Jerry");
		System.out.println(p2);

		// 调用私有属性
		Field name = clazz.getDeclaredField("name");
		name.setAccessible(true);
		name.set(p2, "zhangsan");

		// 调用私有的方法
		Method showNation = clazz.getDeclaredMethod("showNation", String.class);
		showNation.setAccessible(true);
		String nation = (String) showNation.invoke(p2, "中国");// 相当于String nation = p1.showNation("中国");
		System.out.println(nation);

	}
}

反射可以给私有属性,私有方法,私有构造器来设置值。正常的new创建对象是不可以的!

3. 两个疑问(看自己理解)


通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底使用哪个呢?

建议:直接new的方式。

什么时候会使用:反射的方式? 反射的特征:动态性。


反射机制与面向对象中的封装性是不是矛盾的?如何看待两个技术?

不矛盾,封装性提示的是你哪个方法能调用哪个方法不能调用(private),整体上算是一个限制提示建议的效果。

4. java.lang.Class 类的理解


类的加载过程:

程序经过javac.exe 以后,会生成一个或多个字节码文件(.class结尾)。

接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中,这个过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。


提示小结:
Idea项目下的out目录是用来存放.java文件编译后的字节码文件的。


万事万物皆对象!
平常我们是对象.xxx属性 , File对象, URL对象等等。反射同样也是,就是通过Class的类对象,来实现的。

并且Class的实例就对应着一个运行时类,因此我们不能new一个Class,因为他是运行时类本身就存在的。

5. 如何获取Class实例的4中方式


首先,第一点Class运行时类并不是我们自己创建出来的,而是它编译运行后自己有的类。

加载到内存中的运行时类,会缓存一定的时间。在此事件之内,我们可以通过4中不同的方式来获取此运行时类。(也就是只有一个运行时类,只不过获取方式不同。)

package com.test;

import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;


public class ReflectionTest {

	@Test
	public void test3() throws ClassNotFoundException {

		//方式一:调用运行时类的属性:.class
		Class clazz1 = Person.class;
		System.out.println(clazz1);
		//也是可以加泛型的
		//Class<Person> clazz1 = Person.class;

		//方式二:通过运行时类的对象,调用getClass()来获取
		Person p1 = new Person();
		Class clazz2 = p1.getClass();
		System.out.println(clazz2);

		//方式三:调用Class的静态方法:forName(String classPath)
		Class clazz3 = Class.forName("com.test.Person");
		System.out.println(clazz3);

		//我们比较一下他们的地址值,返回都是true,说明他们都是相同的运行时类,只不过获取的方式不同而已。
		System.out.println(clazz1 == clazz2);//true
		System.out.println(clazz1 == clazz3);//true

		//方式四:使用类的加载器:ClassLoader
		ClassLoader classLoader = ReflectionTest.class.getClassLoader();
		Class clazz4 = classLoader.loadClass("com.test.Person");
		System.out.println(clazz4);

		System.out.println(clazz1 == clazz4);//true
	}
}

6. Class实例可以是哪些结构?

package com.test;

import org.junit.jupiter.api.Test;

import java.lang.annotation.ElementType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;


public class ReflectionTest {
	@Test
	public void test4(){
		Class c1 = Object.class;
		Class c2 = Comparable.class;
		Class c3 = String[].class;
		Class c4 = int[][].class;
		Class c5 = ElementType.class;
		Class c6 = Override.class;
		Class c7 = int.class;
		Class c8 = void.class;
		Class c9 = Class.class;

		int[] a = new int[10];
		int[] b = new int[100];
		Class c10 = a.getClass();
		Class c11 = b.getClass();
		//只要元素类型与维度一样,就同一个Class
		System.out.println(c10 == c11);//true
	}
}

7. 类的加载 与 ClassLoader的理解

7.1 类的加载过程


当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化。

在这里插入图片描述


这三个步骤必须牢记!

加载(Load):就是讲class文件字节码内容加载到内存中,转换为运行时数据结构,生成一个代码这个类的java.lang.Class对象。


链接(Link):正式为类变量(static类型)分配内存并设置类变量默认初始值,例如在static int a 在链接这个环节它就会被赋值默认初始值0,String b在链接就被默认赋值为null。


初始化:这个阶段有一个类构造器<clinit>()方法,非常重要,它是由编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生。

当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。

在这里插入图片描述

7.2 类加载器(ClassLoader)的作用


类加载器的作用和类缓存:
在这里插入图片描述


类加载器作用就是用来把类(class)装载进内存的。

在这里插入图片描述

我们平时定义的类,都是通过系统类加载器来架子啊的,因此也算是最常用的加载器了。

package com.test;

import org.junit.jupiter.api.Test;

public class ClassLoadingTest {
    @Test
    public void test1(){
        //对于定义类,使用系统类加载器进行加载
        ClassLoader classLoader = ClassLoadingTest.class.getClassLoader();
        System.out.println(classLoader);//这个就是AppClassLoader系统加载器

        //调用系统类加载的getParent():获取扩展类加载器
        ClassLoader classLoader1 = classLoader.getParent();
        System.out.println(classLoader1);//这个就是ExtClassLoader拓展加载器

        //调用扩展类加载器的getParent(): 无法直接获取引导类加载器的。
        //引导类加载器主要负责加载java的核心类库,它是无法加载自定义类。
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);//这里返回null,并不是没有,而是引导类加载器不能直接获取。

        //引导类加载器加载java的核心类库,例如String类型
        ClassLoader classLoader3 = String.class.getClassLoader();
        System.out.println(classLoader3);//这里也是返回null,说明String的加载器也是引导类加载器。
    }
}

7.3 类加载器(ClassLoader) 加载配置文件Properties案例


我们在jdbc场景下,就有两种加载Properties文件的方式:

  • 读取配置文件方式一:使用FileInputStream方法,此路径默认是当前module工程模块下。
  • 读取配置文件方式二:使用ClassLoader , 此路径默认是当前module的src下。
package com.test;

import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;

public class ClassLoadingTest {

    /*
        Properties:用来读取配置文件。
    */
    @Test
    public void test2() throws Exception {

        Properties pros = new Properties();
        //读取配置文件方式一:使用FileInputStream方法,此路径默认是当前module工程模块下。
        FileInputStream fis = new FileInputStream("jdbc.properties");

        //如果想用这种方式访问jdbc1.properties也是可以的,就是需要配置路径如下
        //FileInputStream fis2 = new FileInputStream("src\\jdbc1.properties");
        pros.load(fis);
        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        System.out.println("姓名:"+user + ", 密码:" +password);

    }

    @Test
    public void test3() throws Exception {

        Properties pros = new Properties();
        //读取配置文件方式二:使用ClassLoader , 此路径默认是当前module的src下。
        ClassLoader classLoader = ClassLoadingTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
        pros.load(is);

        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        System.out.println("姓名:"+user + ", 密码:" +password);

    }
}

8. 反射 newInstance()方法 创建对应的运行时类的对象


clazz.newInstance()方法:调用此方法,创建对应的运行时类的对象。该方法默认调用的就是类的空参构造器。

因此要想此方法能正常创建运行时类的对象,要求:

  • 1.运行时类必须提供空参的构造器。
  • 2.空参的构造器的访问权限得够!通常设置为public。

一个public的空参构造器,在javabean中很重要,原因如下:

  • 1.便于反射,创建运行时类的对象。
  • 2.便于子类继承此运行时类 时,默认调用super()时,保证父类有此构造器。

package com.Reflection;

import com.test.Person;
import org.junit.jupiter.api.Test;

public class NewInstanceTest {

    @Test
    public void test1() throws IllegalAccessException, InstantiationException {

        Class<Person> clazz = Person.class;
        /*
            clazz.newInstance()方法:调用此方法,创建对应的运行时类的对象。
            这里默认调用的就是类的空参构造器。

            因此要想此方法能正常创建运行时类的对象,要求:
            1.运行时类必须提供空参的构造器。
            2.空参的构造器的访问权限得够!通常设置为public。

            一个public的空参构造器,在javabean中很重要,原因如下:
            1.便于反射,创建运行时类的对象。
            2.便于子类继承此运行时类 时,默认调用super()时,保证父类有此构造器。
            
         */
        Person p1 = (Person)clazz.newInstance();
        System.out.println(p1);
    }
}

通过newInstance()方法,来体现反射的一个动态效果:

package com.Reflection;

import com.test.Person;
import org.junit.jupiter.api.Test;

import java.util.Random;

public class NewInstanceTest {

	/*
		下面这种方式就体现了,反射的动态性效果。
	*/
    
    @Test
    public void test2(){

        //要一个随机值,nextInt(3)定义了以3为边界。
        int num = new Random().nextInt(3);//0,1,2
        String classPath = "";
        switch (num){
            case 0:
                classPath = "java.util.Date";
                break;
            case 1:
                classPath = "java.lang.String";
                break;
            case 2:
                classPath = "com.test.Person";
                break;
        }

        try {
            Object obj = getInstance(classPath);
            System.out.println(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    /*
        该方法创建一个指定类的对象。
        classPath:指定类的全类名
     */

    public Object getInstance(String classPath) throws Exception {
        Class<?> clazz = Class.forName(classPath);
        return clazz.newInstance();
    }
}

9. 反射 获取运行时类的属性结构及其内部结构


获取属性结构

  • getFields():获取当前运行时类及其父类中声明为public访问权限的属性.
  • getDeclaredFields():获取当前运行时类中声明的所有属性,并且不包含父类中声明的属性。
package exam.demo2;

import exam.demo.Person;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;

/*
    获取当前运行时类的属性结构
 */
public class FieldTest {

    @Test
    public void test() throws Exception {

		/*
			Person是我自定义的一个类,
			定义了int,String类型属性,创建一些方法,
			设定注解,实现接口等等操作,这里就不添加person源码了,随便设定就可以。
		*/
        Class clazz = Person.class;
        Class clazz2 = Class.forName("exam.demo.Person");

        //获取属性结构
        //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
        Field[] fields = clazz2.getFields();
        for (Field f : fields){
            System.out.println(f);
        }

        System.out.println("*******************");

        //getDeclaredFields():获取当前运行时类中声明的所有属性,并且不包含父类中声明的属性。
        Field[] declaredFields = clazz2.getDeclaredFields();
        for (Field f : declaredFields){
            System.out.println(f);
        }

    }

}

获取属性结构的权限修饰符,数据类型,变量名:

package exam.demo2;

import exam.demo.Person;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/*
    获取当前运行时类的属性结构
 */
public class FieldTest {

    /*
        属性的权限修饰符,数据类型,变量名的获取
     */
    @Test
    public void test2(){
        Class clazz = Person.class;
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field f : declaredFields){

            //1.f.getModifiers()获取当前属性的权限修饰符
            int modifiers = f.getModifiers();
            System.out.println(modifiers);//返回的是int类0,1,2,4
            System.out.println(Modifier.toString(modifiers));

            //2.f.getType()获取当前属性的数据类型
            Class type = f.getType();
            System.out.println(type + ",");
            System.out.println(type.getName());

            //3.f.getName()获取当前属性的变量名
            String name = f.getName();
            System.out.println(name);

            System.out.println("--------------");
        }
    }
}

get.getModifiers()返回值对应类型:
(default类型的值为: 0)
在这里插入图片描述


获取当前运行时类的属性结构的权限修饰符,注解,返回值类型,方法名和参数名 ,抛出异常。

注意如果反射需要接受注解啥的,那么注解的生命周期必须是runtime的!!

原因也很简单,反射是基于.class文件后的,因此注解也必须保留到那个时候。

package exam.demo2;

import org.junit.jupiter.api.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/*
    获取当前运行时类的属性结构的权限修饰符,返回值类型,方法名和参数名 ,抛出异常。
 */
public class FieldTest {

    @Test
    public void test() throws Exception {

        Class clazz = Class.forName("exam.demo.Person");
        Method[] declaredMethod = clazz.getDeclaredMethods();
        for (Method m : declaredMethod){

            //1. m.getAnnotations()方法:获取方法声明的注释
            Annotation[] annotation = m.getAnnotations();
            for (Annotation a : annotation){
                System.out.println(a);
            }

            //2. m.getModifiers()方法:获取权限修饰符
            System.out.print(Modifier.toString(m.getModifiers())+"\t");

            //3. m.getReturnType()方法:返回值类型
            Class<?> returnType = m.getReturnType();
            System.out.print(returnType+"\t");

            //4. m.getName()方法:方法名
            String name = m.getName();
            System.out.print(name+"\t");
            System.out.print("(");

            //5. 形参列表
            Class[] parameterTypes = m.getParameterTypes();
            //没有参数类型的情况和有参数的情况区分
            if (!(parameterTypes == null && parameterTypes.length == 0)){
                for (Class c:parameterTypes){
                    //形参名
                    System.out.print("参数名:"+c.getName());
                }
            }
            System.out.print(")"+"\t");

            //6. 获取抛出异常
            Class<?>[] exceptionTypes = m.getExceptionTypes();
            if (!(exceptionTypes == null && exceptionTypes.length == 0)){

                for (Class c : exceptionTypes){
                    System.out.print("异常:"+c.getName()+"\t");
                }

            }

            System.out.println();
        }
    }

}

10. 反射 获取运行时类的构造器结构

获取构造器结构的方法:

package exam.demo2;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;

public class OtherTest {

    /*
        获取构造器结构
     */

    @Test
    public void test() throws ClassNotFoundException {
        Class clazz = Class.forName("exam.demo.Person");

        //clazz.getConstructors()方法:获取当前运行时类当中声明为public的构造器
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor c : constructors){
            System.out.print(c+"\t");
            System.out.println(c.getName());
        }

        System.out.println("--------------");

        //clazz.getDeclaredConstructors()方法:获取当前运行时类中声明的所有构造器
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor c : declaredConstructors){
            System.out.print(c+"\t");
            System.out.println(c.getName());
        }
    }

}

11. 反射 获取父类或父类泛型结构

获取运行时类的父类及其父类泛型。

package exam.demo2;

import exam.demo.Person;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class OtherTest {

    /*
        获取运行时类的父类
     */
    @Test
    public void test2(){

        Class clazz = Person.class;
        //clazz.getSuperclass()方法:获取运行时的父类。
        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);
        System.out.println(superclass.getName());

    }

    @Test
    public void test3(){
        Class clazz = Person.class;

        //clazz.getGenericSuperclass()方法:获取带泛型的父类。
        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);

    }

    @Test
    public void test4(){

        //获取运行时类的带泛型的父类的泛型
        Class clazz = Person.class;
        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) genericSuperclass;

        Type[] actualTypeArguments = paramType.getActualTypeArguments();
        System.out.println(actualTypeArguments[0].getTypeName());

    }
}

12. 反射 获取运行时类实现的接口,包,注解结构

package exam.demo2;

import exam.demo.Person;
import org.junit.jupiter.api.Test;

import java.lang.annotation.Annotation;


public class OtherTest {

    /*
        获取运行时类实现的接口结构
     */
    @Test
    public void test(){
        Class clazz = Person.class;

        //clazz.getInterfaces()方法:获取运行时类实现的接口。
        Class[] interfaces = clazz.getInterfaces();
        for (Class c : interfaces){
            System.out.println(c);
        }

        //clazz.getSuperclass().getInterfaces()方法:获取运行时类的父类的接口信息。
        Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
        for (Class c : interfaces1){
            System.out.println(c);
        }
    }

    /*
        获取运行时类所在的包
     */
    @Test
    public void test2(){

        Class clazz = Person.class;

        Package aPackage = clazz.getPackage();
        System.out.println(aPackage);

    }

    /*
        获取运行时类声明的注解
     */
    @Test
    public void test3(){
        Class personClass = Person.class;
        Annotation[] annotations = personClass.getAnnotations();
        for (Annotation a : annotations){
            System.out.println(a);
        }
    }

    
}

13. 反射 调用运行时类中指定属性

调用运行时类中指定的结构:属性,方法,构造器:

package exam.demo2;

    /*
        调用运行时类中指定的结构:属性,方法,构造器
    */

import exam.demo.Person;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;

public class ReflectionTest {

    @Test
    public void testField() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        Class clazz = Person.class;

        /*
            clazz.getField("id")方法:获取指定的属性,这里也是只能获取public类型的属性。通常不采用该方式!
         */
        Field id = clazz.getField("id");
        System.out.println(id);

        //创建运行时类对象
        Person p = (Person)clazz.newInstance();
        //id.set(p,xxx)方法:设置参数
        id.set(p,100);
        //id.get(p)方法:获取p的id的属性值
        int i = (int)id.get(p);//可以强转一下
        System.out.println(i);

        /*
            clazz.getDeclaredField("name")方法比较推荐,因为它可以修改所有权限。
         */
        Field name = clazz.getDeclaredField("name");

        //name.setAccessible(true)方法:对于private和默认类型等等,我们必须设置它的Accessible为true才能进行设置修改!
        name.setAccessible(true);

        name.set(p,"zhangsan");
        String str = (String)name.get(p);
        System.out.println(str);


        System.out.println("=================");

        //
        Field[] field = clazz.getFields();
        for (Field f: field){
            System.out.println(f);
        }
        System.out.println("===================");

        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field f:declaredFields){
            System.out.println(f);
        }
    }

}

14. 反射 调用运行时类中的指定方法

调用运行时类的方法,并设置参数:

package exam.demo2;

import exam.demo.Person;
import org.junit.jupiter.api.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionTest {

    /*
        调用运行时类的方法,并设置参数
     */
    @Test
    public void testMethod() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class aClass = Class.forName("exam.demo.Person");
        Person p = (Person)aClass.newInstance();

        //1. getDeclaredMethod("xxx",参数类型.class)方法:获取指定的某个方法 , 参数1:方法名,参数2:指明获取方法的形参列表。
        Method declaredMethod = aClass.getDeclaredMethod("show", String.class);

        //注意这里也要设置setAccessible(true)的方法!不然遇到private等其他类型可能就无法执行。
        declaredMethod.setAccessible(true);

        //declaredMethod.invoke()方法: 参数1:方法调用者的对象,参数2:给方法传递的形参。
        //此外,invoke()方法的返回值也是调用方法的返回值。
        Object returnvalue = declaredMethod.invoke(p, "zhangsan");
        System.out.println(returnvalue);


        System.out.println("方法有静态方法,那么如何调用静态方法呢?? 见下:");

        Method showDesc = aClass.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        Object returnValue2 = showDesc.invoke(Person.class);//因为是静态的么,直接用他的class文件就行。
        System.out.println(returnValue2);//没有返回值就是null
        
    }

}

15. 反射 调用运行时类中的指定的构造器

调用反射运行时类的构造器:

package exam.demo2;

import exam.demo.Person;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectionTest {
    /*
           调用反射运行时类的构造器:
     */

    @Test
    public void testConstructor() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Person> personClass = Person.class;

        //1.getDeclaredConstructor(String.class)方法:获取指定的构造器,参数指明构造器的参数列表。
        Constructor<Person> constructor = personClass.getDeclaredConstructor(String.class);
        //同样setAccessible(true)来确保不受权限保护。
        constructor.setAccessible(true);
        //constructor.newInstance()方法来调用创建运行时的对象
        Person p = constructor.newInstance("zhangsan");
        System.out.println(p.toString());

    }
}

16. 工厂模式下的反射效果


首先创建两个类,Emp 和 Student类,模拟工厂的作用就是创建他们的两个对象。

Emp类:

package factory;

public class Emp {

    private int empno;
    private String ename;

    public int getEmpno() {
        return empno;
    }

    public void setEmpno(int empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }
}

Student类:

package factory;

public class Student {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Invokefactory类,分别演示了 不使用反射 和 使用反射的一个效果:

package factory;

import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class InvokeFactory {

    //我们平时的工厂模式,是拿到零件创建出所需要的东西,这里我们模拟要求创建出不同的对象来

    //批量生成Emp对象
    public static Emp getEmp(){
        Emp emp = new Emp();
        return emp;
    }

    //批量生成Student对象
    public static Student getStudent(){
        Student student = new Student();
        return student;
    }

    //不使用反射来操作的效果,很差一百个类的对象需要创建一百个对应类的方法,如果出现新的类对象,也需要改动很费劲,
    //开发中也不可能这么操作的。
    //但是使用反射后,工厂模式就仅仅需要一个方法来应对所有不同的对象。

    //使用反射方式来操作的工厂模式,这里的classPath就是反射要用的字节类路径
    public static Object getObject(String classPath) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Object obj = null;
        Class<?> aClass = Class.forName(classPath);
        //Object o = aClass.newInstance();
        Constructor<?> constructor = aClass.getDeclaredConstructor();
        obj = constructor.newInstance();
        return obj;
    }

    @Test
    public void test() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //不用反射案例:
        //工厂类直接获取,但是如果不知道再不清楚java里面的结构就完全不能执行了。
        //并且这里是一个对应一个方法,一对一很繁琐。
        Emp emp = InvokeFactory.getEmp();
        Student student = InvokeFactory.getStudent();

        //使用反射案例:
        //不确定是哪个对象,我们可以通过反射达到一个一对多的一个效果。
        Object object = InvokeFactory.getObject("factory.Emp");
        Object object1 = InvokeFactory.getObject("factory.Student");
    }

}

通过上面可以看出反射很重要,尤其到了框架的内容都是操作反射和动态代理!

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-14 15:48:10  更:2021-12-14 15:48:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:47:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码