Java基础增加二
枚举
为什么要有枚举
问题:要定义星期几或性别的变量,该怎么定义?假设1-7分别表示星期一到星期日,但有人可能会写成int weekday = 0;
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。
模拟枚举示例:
// 定义一个类来模拟枚举 publicabstractclass WeekDay {
private WeekDay() {}
publicstaticfinal WeekDayMON =new WeekDay(){
@Override public WeekDay nextDay() { returnTUR; } }; publicstaticfinal WeekDayTUR =new WeekDay(){
@Override public WeekDay nextDay() { returnWEN; } }; publicstaticfinal WeekDayWEN =new WeekDay(){
@Override public WeekDay nextDay() { returnnull; } };
publicabstract WeekDay nextDay();
//重写toString方法 public String toString() { returnthis ==MON ?"MON" : (this ==TUR) ?"TUR":(this ==WEN) ?"WEN" :null; } } |
// 枚举 publicclass EnumTest {
publicstaticvoid main(String[] args) {
WeekDay weekDay = WeekDay.MON;
System.out.println(weekDay.nextDay()); } } |
真正的枚举示例:
// 枚举 publicclass EnumTest {
publicstaticvoid main(String[] args) {
WeekDay weekDay2 = WeekDay.FRI; //枚举默认输出元素名字 System.out.println(weekDay2); //得到枚举元素的名字 System.out.println(weekDay2.name()); //查看本元素在所有枚举元素的位置 System.out.println(weekDay2.ordinal()); //把一个字符串变成所表示的枚举类型 System.out.println(WeekDay.valueOf("SUN")); //把所有的枚举元素变为数组 System.out.println(WeekDay.values().length); }
// 真正的枚举自动帮我们实现了toString方法 publicenum WeekDay { SUN,MON,TUE,WED,THI,FRI,SAT } } |
带构造方法的枚举:
publicenum WeekDay { //所定义的别的东西需要在元素之后并且最后一个元素加分号 //在元素后带括号可以指定构造方法 SUN(1),MON,TUE,WED,THI,FRI,SAT; private WeekDay() { System.out.println("first"); } private WeekDay(int day) { System.out.println("second"); } } |
我试了一下,貌似不管元素后的括号里带什么数字,它都调用第二个构造方法,我写了第三个构造方法结果还是如此。不知道内部到底是怎么写的。
带抽象方法的枚举:
publicenum TrafficLamp { RED(30) { @Override public TrafficLamp nextLamp() { returnGREEN; } },GREEN(45) { @Override public TrafficLamp nextLamp() { returnYELLOW; } },YELLOW(5) { @Override public TrafficLamp nextLamp() { returnRED; } }; publicabstract TrafficLamp nextLamp(); privateinttime; private TrafficLamp(int time) { this.time = time; } } |
当枚举只有一个成员时,可以用来当作单例的一种实现方式。
反射
反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也是用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们的是Field、Method、Contructor、Package等等。
反射的基石——>Class类
示例代码如下:
// 反射 publicclass ReflectTest {
publicstaticvoid main(String[] args)throws ClassNotFoundException {
String str1 = "abc"; Class cls1 = str1.getClass(); Class cls2 = String.class; Class cls3 = Class.forName("java.lang.String"); //看他们是不是同一份字节码 System.out.println(cls1 == cls2); System.out.println(cls1 == cls3);
//看cls1是不是基本类型 System.out.println(cls1.isPrimitive()); System.out.println(int.class.isPrimitive()); System.out.println(int.class == Integer.class); System.out.println(int.class == Integer.TYPE);
System.out.println(int[].class.isPrimitive());
} } |
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如:int[],void。然后可以调用一些方法,如isPrimitive()可以查看它是不是基本类型。
Constructor类:
Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
例子:Constructor[] constrctors = Class.froName(“java.lang.String”).getConstructors();
得到某一个构造方法:
例子:Constructor constructor = Class.forName(“java.lang.String”)
.getConstructor(StringBuffer.class);
// 获取方法时要用到类型
创建实例对象:
通常方式: String str = new String(new StringBuffer(“abc”));
反射方式:String str = (String)constructor.newInstance(new StringBuffer(“abc”));
// 调用获得的方法时要用到上面相同类型的实例对象
Class.newInstance()方法:
例子:String obj = (String)Class.forName(“java.lang.String”).newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。
Field类:
Field类代表某个类啵的一个成员变量
演示:
// 演示用 publicclass ReflectPoint {
privateintx; publicinty;
public ReflectPoint(int x,int y) { super(); this.x = x; this.y = y; }
} |
// 反射 publicclass ReflectTest {
publicstaticvoid main(String[] args)throws Exception{
ReflectPoint pt1 = new ReflectPoint(3, 5); Field fieldY = pt1.getClass().getField("y"); //fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值 System.out.println(fieldY.get(pt1));
Field fieldX = pt1.getClass().getDeclaredField("x"); //启用暴力反射,私有的也能访问 fieldX.setAccessible(true); System.out.println(fieldX.get(pt1)); } } |
如果是私有的需要用getDeclaredField()去访问,然后再开启暴力反射。
对字节的比较用==来。因为只存在一份。
成员变量反射综合案例:
把字符串变量中的所有’b’改为’a’:
publicclass ReflectPoint {
public Stringstr1 ="ball"; public Stringstr2 ="basketball"; public Stringstr3 ="funfang";
@Override public String toString() { returnstr1 +":" +str2 + ":" +str3; } } |
publicclass ReflectTest {
publicstaticvoid main(String[] args)throws Exception{
changeCharValue(pt1); System.out.println(pt1);
}
privatestaticvoid changeCharValue(ReflectPoint pt1)throws Exception {
Field[] fields = pt1.getClass().getFields(); for (Field field : fields) { //判断成员变量的类型是不是String if (field.getType() == String.class) { String oldValue = (String) field.get(pt1); StringnewValue = oldValue.replace('b','a'); field.set(pt1, newValue); } } } } |
Method类:
Method类代表某个类中的一个成员方法
得到类中的某一个方法:
例子:Method charAt = Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
调用方法:
通常方法:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoide(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,这胡着什么样的意义呢?说明该Method对象对应的是一个静态方法!
-----------------未完待续---------------------