黑马程序员——枚举与反射

本文介绍了Java中的枚举和反射概念。枚举用于定义常量对象,并具备类的特性,可以实现单例模式。枚举示例为交通灯。反射部分讲解了获取Class对象的三种方式,以及Class对象的isPrimitive()、isArray()等方法,还涉及Method、Constructor和Field类的使用,包括newInstance()方法和暴力反射。最后提到了数组在反射中的处理以及如何通过用户提供的类名执行main方法。
摘要由CSDN通过智能技术生成

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

枚举

枚举:定义一些常量的对象,而且,这些对象可以符合某一类事物的具体属性,方法。如:星期一到星期天,交通灯的红绿黄灯,等等。

枚举的特性,如下代码:

package com.ken;
public class TestEnum {
	/**
	 * 最简单的枚举例子
	 */
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		System.out.println(WeekDay.SAT);//因为枚举的元素是静态的常量,所以类名直接调用
		System.out.println(WeekDay.valueOf("FRI"));
		System.out.println(WeekDay.MON.ordinal());
		//可以推测,枚举是一个类,里面其实是帮我们封装好了很多方法,这些我们都不能看到,因为我用的开发平台是Eclipse,所以它依靠反射来提示枚举里面有什么方法
	}
	
	public enum WeekDay{			//可以看成一个类,此处是成员内部类
		SUN,MON,TUE,WED,THI,FRI,SAT;//后面的分号可写可不写,不过在此行后面(元素列表)还有代码的话就必须写
	}
}

枚举更像一个类,一个将自己的构造方法私有化,然后让自己的元素来用自己的构造方法来new对象,然后对外提供这些对象常量的类。

所以一旦加载了枚举,元素列表将会自动初始化,即每个元素都会执行相应的构造方法·。

所以说,枚举可以简单的实现一个单例模式!


下面的例子比较复杂,可以好好的复习,学习透彻!(交通灯枚举)

package com.ken;
public enum TrafficLamp {
	RED(40){					//其实几个元素都是匿名内部类,调用的是父类有参的构造方法,这个time是指交通灯的时间
		public TrafficLamp nextLamp(){		//实现父类的抽象方法
			return GREEN;
		}
	},
	YELLOW(5){
		public TrafficLamp nextLamp(){
			return RED;
		}
	},
	GREEN(40){
		public TrafficLamp nextLamp(){
			return YELLOW;
		}
	};
	private int time;				//此处会提示time没有被用到,无所谓,只是演示而已
	private TrafficLamp(int time){			//私有的构造方法,是不是改成protect更加合适点!
		this.time=time;				//还是private合适,因为元素都是在枚举里面(类里面了)
		}
	public abstract TrafficLamp nextLamp();<span style="white-space:pre">		</span>//抽象方法,让子类实现,并且可被外部访问
}

上述代码编译后会形成3个匿名类文件,其实枚举帮我们实现了一些方法(第一个例子就体现出来了),但是我们并看不到这些代码,但却能找到这些类文件,这些文件我们也并看不懂,所以,就有了反射,即加载类文件然后能够得到该类文件的方法和字段等等。反射就是有这个好处,不过,却忽略了具体的实现细节,因为这些细节我们并不知道的。


反射

Class类:得到Class类的方法有三个(Class类就是各个字节码对应的实例对象)

①对象.getClass

②class.forName("java.util.Date");//主要用这种方法,里面要写完整的类名

③类名.class


九个预定义的class对象:八个基本类型对应八个class对象void对应一个class对象


方法:

isPrimitive()判断Class对象是否为基本数据类型


int.class==Integer.class      false

int.class==Integer.TYPE      true


int[].class.isPrimitive()       false

int[].class.isArray()             true是数组类型的class实例对象

总之,只要在源程序中出现的类型,都有各自的Class实例对象


Method:表示类中的方法类型。


Constructor:表示类中的构造函数类型。

Constructor con=String.class.getConstructor(StringBuffer.class);

con.newInstance(new StringBuffer("abc"));


newInstance不只是Constructor的方法,Class中也有此方法(实例化无参构造函数)


Filed:表示成员变量的类

ReflectPoint pt1=new ReflectPoint(3,5);//省略掉ReflectPoint类,其中构造方法为ReflectPoint(x,y)其中,x为private修饰,y为public修饰

Field fieldY=pt1.getClass.getField("y");//注意:filedY的值不是pt1对象身上的

fieldY.get(pt1);//这个才是取pt1上的“y”值

Filed filedX=pt1.getDeclaredField("x");//能看到不可见的字段

filedX.setAccessible(true);//暴力反射,使之能够被访问


对字节码的比较不用equal而直接用“==”


Method:方法类

可通过Class类对象获得,里面的方法有

invoke(对象,此方法的参数)

invoke(null,此静态方法的参数)//不通过对象调用的方法就是静态方法了


写一个程序,这个程序能够根据用户提供的类名,去执行该类的main方法

package com.ken;
import java.lang.reflect.InvocationTargetException;

public class TestArguments {
	public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		//正常调用的话:TestAeguments.main(new String[]{"343","2323"})
		for(String arg:args){
			System.out.print(arg);
		}
		
	}
}

package com.ken;

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

public class Test {

	/**
	 * @param args
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 * @throws ClassNotFoundException 
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 */
	public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException {
		String startingClassName=args[0];
		Method mainMethod=Class.forName(startingClassName).getMethod("main",String[].class);
		//mainMethod.invoke(null, new String[]{"1","2","3"});//要从类型 Method 中调用 varargs 方法 invoke(Object, Object...),应该将类型为 String[] 的参数显式地强制转换为 Object[]。对于 varargs 调用来说,也可以将其强制转换为 Object
		//这个地方比较难理解
		mainMethod.invoke(null, new Object[]{new String[]{"1","2","3"}});//解决方案①
		//mainMethod.invoke(null, (Object)new String[]{"1","2","3"});//解决方案②
		

	}

}

在运行Test的时候要配置一下参数如下图所示:


数组:具有相同元素类型及相同维度的数组都属于同一个class

Arrays.asList(arr)//整数类型的数组会被整一个当成数组对象存入list中;而String对象数组则会将一个一个String对象存入list。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值