黑马程序员——反射问题代码学习点

本文深入讲解Java反射机制的基础知识及应用场景,包括如何获取Class对象、访问私有成员变量、调用方法等内容,并通过实例演示了如何利用反射实现简单框架。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

---------------ASP.Net+Android+IOS开发、.Net培训、期待与您交流! -----------

反射问题代码学习点

反射掌握不太好 在网上搜索学习一些代码

例题一:

import java.util.Arrays;
import java.util.Date;

/**
 * 很重要的一个知识:反射
 * @author wangyang
 * 反射就是把Java类中的各种成分映射成相应的java类。
 * 反射不是jdk1.5的新特性。
 * 反射会使程序的性能严重下降。
 * Class类代表了各个Java类。它的实例对象是各个类在内存中的二进制码。
 * 例如:Person类的字节码。Date类的字节码。
 * 1.如何得到Class类的实例对象呢?
 *   有三种方法。
 * 2.九种预定义的Class对象。
 * 	 八种基本数据类型,和void。它们的字节码对象不用创建。
 * 3.数组类型的Class对象。
 *   
 *
 */

public class ClassDemo
{
	private Date birthday = new Date();
	public Date getBirthday()
	{
		return birthday;
	}

	public void setBirthday(Date birthday)
	{
		this.birthday = birthday;
	}
	private int x ;
	private int y;
	private String a;
	private String b;
	private String c;
	
	public ClassDemo(String a, String b, String c)// 这个构造方法是因为ClassDemo2中的练习而创建的。
	{
		super();
		this.a = a;
		this.b = b;
		this.c = c;
	}
	
	public int getX()
	{
		return x;
	}

	public void setX(int x)
	{
		this.x = x;
	}

	public int getY()
	{
		return y;
	}

	public void setY(int y)
	{
		this.y = y;
	}

	@Override
	public String toString()
	{
		return "ClassDemo [a=" + a + ", b=" + b + ", c=" + c + "]";
	}

	public ClassDemo(int x, int y)//这个构造方法是因为ClassDemo2中的练习而创建的。
	{
		super();
		this.x = x;
		this.y = y;
	}	
	
	public ClassDemo()
	{
		// TODO Auto-generated constructor stub
	}

	public static void main(String[] args) throws Exception
	{
		//demo_1();
		//demo_2();
		System.out.println(Arrays.asList(args));//用于ClassDemo2的练习。
	}
	private static void demo_1() throws Exception//如何得到Class的实例对象呢?
	{
		Class<String> c1 = String.class;//这是第一种方法。
		
		@SuppressWarnings("unchecked")
		Class<String> c2 = (Class<String>) new String().getClass();//用对象调用getClass()。这个方法定义在Object里面的。
		
		//这种方法得到Class的实例对象是最常用的。从配置文件中读取一个字符串,传递给forName()这个方法。
		Class<?> c3 = Class.forName("java.lang.String");//使用Class的静态方法。返回一个Class实例对象。此方法会抛出异常。
		
		System.out.println(c1==c2);//都是同一个对象。
		System.out.println(c1==c3);
	}
	private static void demo_2()//基本数据类型的Class。
	{
		Class<Integer> i = int.class;  //它和Integer.class是不同的。
		Class<Integer> i2 = Integer.class;
		
		System.out.println("int.class==Integer.class:  "+(i==i2));
		System.out.println("i.isPrimitive():  "+i.isPrimitive());
		System.out.println("i==Integer.TYPE:  "+(i==Integer.TYPE));//基本数据类型包装类,有一个常量,TYPE可以返回一个属性是基本数据类型的Class对象
		System.out.println("int[].class.isArray():  "+int[].class.isArray());//数组类型的Class实例对象。
	}
}

例题二

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 反射
 * @author wangyang
 * 反射一个类的构造函数。constructor
 *   要注意的是,当返回构造函数对象的时候,需要的参数是class的对象。
 *   当返回的是构造函数生成的对象时。需要的是这个对象的构造函数的参数。
 *   
 * 反射一个类的成员变量。field
 *    反射成员变量时,就算是私有的也可以访问。
 *    不过既然私有就是不想让人访问,还是不访问的好。
 *    作业:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。
 *    
 * 反射一个类的方法。method
 *    注意的是。如果一个方法的参数是数组的话,invoke方法会自动拆包。
 *    所以要在数组前要加上一个(Object),告诉编译器,这是一个参数。不是一堆参数。
 * 
 * 反射一个类的包。package
 * 
 * 反射一个数组。array
 * 	  
 */
public class ClassDemo2
{
	public static void main(String[] args) throws Exception
	{
//		demo_1();
//		demo_2();
//		demo_3();
//		demo_4();
//		demo_5();
		demo_6();
		
	}

	private static void demo_6()//反射一个数组。
	{
		int[] i1 = new int[]{1,2,3};	
		int[] i2 = new int[4];			
		String[] s1 = new String[]{"a","b","c"};	
		int[][] i3 = new int[3][];	
		
		System.out.println(i1.getClass()==i2.getClass());//同一个类型号的数组,同一种维度。它们的Class对象相同
		System.out.println(i3.getClass().getName());//同一个类型号的数组,同一种维度。它们的Class对象相同,否则不同
		System.out.println(s1.getClass().getName());//同一个类型号的数组,同一种维度。它们的Class对象相同,否则不同
		
		System.out.println(i1.getClass().getSuperclass());//每个数组的父类都是Object.
		
//		Object[] o1 = i1;//是错误的,因为int不是Object的。
		Object[] o2 = s1;//是对的。因为String是Objectr的。
		Object[] o3 = i3;//是对的。因为数组是Object的。
		
		//深入解析Array.asList()方法;
		System.out.println(Arrays.asList(i1));//得到一个结论,基本数据类型的数组是一个Object的子类。不是Object[]。
		System.out.println(Arrays.asList(s1));	
	}

	private static void demo_5() throws Exception//反射一个类的main方法。
	{
		Class c1 = new ClassDemo().getClass();
		
		Method main = c1.getMethod("main", String[].class);
		
		main.invoke(null,(Object)new String[]{"abc","wang","yang"});
		//值得注意是的。如果传入的是一个数组,记得强转成一个Object,因为jdk1.4之前,没有可变参数。
		//这个地方传入的是一个数组。它就会自动拆包,解析成多个参数。
		
	}

	private static void demo_4() throws Exception//反射一个类的成员方法。
	{
			String str1 = "abc";//通过对象获取对象的Class对象,再调用getMethod方法,返回一个指定的Method对象。
			Method mothod = str1.getClass().getMethod("charAt", int.class);
			
			//用指定的Method对象的invoke方法。传入一个对象,一个参数(参数是数组的时候有点不同),返回一个值,这个会值是Object类型的。
			char s =  (Character) mothod.invoke(str1, 2);
			
			System.out.println(s);
	}

	private static void demo_3()throws Exception//反射一个成员变量的练习。
	{
		ClassDemo cd = new ClassDemo("ball","basketball","itcast");
		System.out.println(cd);//先打印一下成员变量的值。
		
		Field[] fieldabc = cd.getClass().getDeclaredFields();
		
		AccessibleObject.setAccessible(fieldabc, true);
		
		for(Field field : fieldabc)
		{
			if(field.getType()==String.class)
			{
				String str = (String) field.get(cd);
				str = str.replace("b","c");
				field.set(cd, str);
			}
		}
		System.out.println(cd);//打印修改后成员变量的值。
	}

	private static void demo_2() throws Exception//反射一个成员变量。
	{
		ClassDemo cd = new ClassDemo(3,6);	
		
		//通过对象获得对应的Class对象。再获取指定的成员变量对象。注意的是:获取的不是成员变量的值。
		Field fieldx = cd.getClass().getDeclaredField("x");
		
		//如果要访问类中私有的成员变量,就要用下面这步,暴力反射。
		fieldx.setAccessible(true);
		
		//获取指定对象对应的这个成员变量的值。。注意:返回的是object。
		int x = (Integer)fieldx.get(cd);
		
		System.out.println(x);
	}

	private static void demo_1() throws Exception//反射一个Class对象的构造函数。
	{
		// 反射一个String的构造函数。记得加泛型。
		Constructor<String> constructor1 = String.class.getConstructor(StringBuffer.class);//这个方法的参数是可变参数。
		
		//通过String的构造函数(其中的参数已经确定)创建一个String对象。
		String str = constructor1.newInstance(new StringBuffer("123"));
		System.out.println(str);
		
		//创建无参的对象。可以用Class类中的newInstance方法。
		str = String.class.newInstance();
	}
}

例题三:

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

/**反射的最重要的应用:
 * 
 * 框架:
 * 什么是框架呢?
 * ex:我做房子卖给用户住,由用户自己安装门窗和空调,
 *    我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。
 *    框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。
 *    
 * 加载资源文件的方式:
 * java加载资源文件是从用户当前活动目录加载的。
 * ex:C:\Users\wangyang>  这个目录就是当前活动目录。
 *    F:\>  这个目录就是当前活动目录。你进入哪个目录,哪个就是当前活动目录。
 * 
 * 1.getRealPath:\金山\配置文件。
 *  这是第一种。先拿到金山的目录。再拿到配置文件的目录。
 *  
 * 2.类加载器。
 *  主要作用。加载类文件。在指定的classpath目录加载类文件,同时还可以加载配置文件。
 *  ClassDemo3.Class.getClassLoader().getResourceAsStream("java0917\config.properties");
 *  返回的是InputStream();只有读文件的功能。
 *  
 * 3.Class的方法。
 *  相当于简化了类加载器。
 *  ClassDemo3.Class.getResourceAsStream("config.properties");
 *  返回的也是InputStream();只能读文件。这个方法的参数,不用指定目录。更聪明。
 *  
 * @author wangyang
 * 利用反射,自己做一个很小的框架。
 * 把用户要指定的集合存在一个文件中。
 * 
 * 这个例子很好。
 */
public class ClassDemo3
{
	public static void main(String[] args) throws Exception
	{
		/**
		 * 第一步:把配置文件加入内存。
		 */
//		InputStream is = new FileInputStream("config.properties");//这是一种,把配置文件放在活动目录下。
//		InputStream is = ClassDemo3.class.getClassLoader().getResourceAsStream("java0917\\config.properties");//这是用类加载器。把配置文件放在classpath路径下。
		InputStream is = ClassDemo3.class.getResourceAsStream("config.properties");//这是用Class的方法。
		Properties pro = new Properties();
		pro.load(is);
		is.close();
		
		/**
		 * 第二步:把配置文件变成具体的类。
		 */
		String classname = (String) pro.get("classname");
		@SuppressWarnings("unchecked")
		Collection<Demo> collection = (Collection<Demo>) Class.forName(classname).newInstance();
		
		/**
		 * 第三步:使用这个类。
		 */
		Demo d1 = new Demo(1,1);
		Demo d2 = new Demo(2,2);
		Demo d3 = new Demo(1,1);
		
		collection.add(d1);
		collection.add(d2);
		collection.add(d3);
		
		System.out.println(collection.size());
		
	}
}

配置文件

config.properties
classname=java.util.HashSet  

 
---------------ASP.Net+Android+IOS开发、.Net培训、期待与您交流! -----------



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值