------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个匿名类文件,其实枚举帮我们实现了一些方法(第一个例子就体现出来了),但是我们并看不到这些代码,但却能找到这些类文件,这些文件我们也并看不懂,所以,就有了反射,即加载类文件然后能够得到该类文件的方法和字段等等。反射就是有这个好处,不过,却忽略了具体的实现细节,因为这些细节我们并不知道的。
反射
①对象.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。