1. 抽象方法的使用
如果一个方法中大量出现if语句, 那么, 就应该考虑使用抽象来处理. 如下例:
package com.lxl; public class Weekend { //周日 public static Weekend SUN = new Weekend(); //周一 public static Weekend MON = new Weekend(); //周二 public static Weekend TUE = new Weekend(); //周三 public static Weekend WES = new Weekend(); //周四 public static Weekend TUR = new Weekend(); //周五 public static Weekend FRI = new Weekend(); //周六 public static Weekend SAR = new Weekend(); /* * 有一个if语句用来判断, 当前日期的下一个日期是星期几. */ public Weekend nextDay(Weekend day){ if(day == SUN) { return MON; }else if(day == MON){ return TUE; }else if(day == TUE){ return WES; }else if(day == WES){ return TUR; }else if(day == TUR){ return FRI; }else if(day == FRI){ return SAR; }else if(day == SAR){ return SUN; }else{ return null; } } public static void main(String[] args) { Weekend sun = Weekend.SUN; sun.nextDay(sun); } }
在这个方法中, 我定义了一周七天. 如果我想知道明天是星期几, 那么我需要写一个if语句, 大量的 if语句来判断, 明天是星期几. 当程序中出现大量的if语句的时候, 就要想到这样的程序不完美, 需要优化. 比如, 我现在有星期八了, 那么你出来需要添加星期八, 还需要修改if语句.
使用抽象来代替if语句.是一个好办法.
修改后的方法如下: 定义了一个抽象方法nextDay
package com.lxl; public abstract class Weekend { //周日 public static Weekend SUN = new Weekend(){ @Override public Weekend nextDay(Weekend day) { return MON; } }; //周一 public static Weekend MON = new Weekend(){ @Override public Weekend nextDay(Weekend day) { return TUE; } }; //周二 public static Weekend TUE = new Weekend(){ @Override public Weekend nextDay(Weekend day) { return WES; } }; //周三 public static Weekend WES = new Weekend(){ @Override public Weekend nextDay(Weekend day) { return TUR; } }; //周四 public static Weekend TUR = new Weekend(){ @Override public Weekend nextDay(Weekend day) { return FRI; } }; //周五 public static Weekend FRI = new Weekend(){ @Override public Weekend nextDay(Weekend day) { return SAR; } }; //周六 public static Weekend SAR = new Weekend(){ @Override public Weekend nextDay(Weekend day) { return SUN; } }; /* * 当有大量的if语句时, 要考虑如何优化 */ /*public Weekend nextDay(Weekend day){ if(day == SUN) { return MON; }else if(day == MON){ return TUE; }else if(day == TUE){ return WES; }else if(day == WES){ return TUR; }else if(day == TUR){ return FRI; }else if(day == FRI){ return SAR; }else if(day == SAR){ return SUN; }else{ return null; } }*/ //定义一个抽象方法 public abstract Weekend nextDay(Weekend day); public static void main(String[] args) { Weekend sun = Weekend.SUN; sun.nextDay(sun); } }
采用抽象方法定义nextDay, 就是可以将if..else转换为独立的类.
这样做的好处是, 一旦有了星期八, 那么只需要定义星期八这个常量就好了, 不用修改其他地方.
2. 枚举
package com.lxl; public class Weekend2 { //这时一个枚举内部类 public enum Weekend { //枚举中每一项,实际上都是这个类的一个子类 MON, TUE, WEN, THI, FRI, SAT, SUN } public static void main(String[] args) { //1. 选择的时候, 只能在枚举范围内进行选择 Weekend day = Weekend.MON; } }
重点:1. 枚举类中每一个元素都是这个类的子类. 下面的操作更能说明这一点. 2. 枚举类对可选的对象做了范围限定
package com.lxl; public class Weekend2 { //这时一个枚举内部类 public enum Weekend { //枚举中每一项,实际上都是这个类的一个子类 MON, TUE, WEN, THI, FRI, SAT, SUN } public static void main(String[] args) { //1. 选择的时候, 只能在枚举范围内进行选择 Weekend day = Weekend.MON; //2. 可用的方法 // 打印名字 System.out.println(day.name()); // 序号 System.out.println(day.ordinal()); // 将某个字符串转换为枚举类型 System.out.println(day.valueOf("MON")); //获取枚举列表 System.out.println(Weekend.values().length); } }
运行结果
MON 0 MON 7
package com.lxl; public class Weekend2 { //这时一个枚举内部类 public enum Weekend { //枚举中每一项,实际上都是这个类的一个子类 MON(), TUE(1), WEN, THI, FRI, SAT, SUN; //3. 为枚举添加构造方法 private Weekend(){System.out.println("first");} private Weekend(int i){System.out.println("second");} } public static void main(String[] args) { //1. 选择的时候, 只能在枚举范围内进行选择 Weekend day = Weekend.MON; //2. 可用的方法 // 打印名字 System.out.println(day.name()); // 序号 System.out.println(day.ordinal()); // 将某个字符串转换为枚举类型 System.out.println(day.valueOf("MON")); //获取枚举列表 System.out.println(Weekend.values().length); } }
输出结果
first second first first first first first MON 0 MON 7
从结果中可以看出一下几点
package com.lxl; public class EnumTest3 { //交通信号灯 public enum TrafficLamp{ RED { @Override public TrafficLamp nextLamp() { return YELLOW; } }, YELLOW { @Override public TrafficLamp nextLamp() { return BLUE; } }, BLUE { @Override public TrafficLamp nextLamp() { return RED; } }; //下一个亮的信号灯--抽象方法 public abstract TrafficLamp nextLamp(); } public static void main(String[] args) { TrafficLamp red = TrafficLamp.RED; System.out.println(red.nextLamp()); } }
运行结果:
YELLOW
从这个demo可以得出以下结论:
package com.lxl; public class EnumTest3 { //交通信号灯 public enum TrafficLamp{ RED(30) { @Override public TrafficLamp nextLamp() { return YELLOW; } }, YELLOW(45) { @Override public TrafficLamp nextLamp() { return BLUE; } }, BLUE(5) { @Override public TrafficLamp nextLamp() { return RED; } }; //下一个亮的信号灯--抽象方法 public abstract TrafficLamp nextLamp(); public int time; private TrafficLamp(int time){ this.time = time; }
public String toString(){
return this.name() + " 亮灯时间: " + time;
}
} public static void main(String[] args) { TrafficLamp red = TrafficLamp.RED; System.out.println(red.nextLamp()); } }
运行结果
YELLOW 亮灯时间: 45
结论
3. 反射
String str = "abc"; Class cla1 = str.getClass(); Class cla2 = String.class; Class cla3 = Class.forName("java.lang.String"); /* * 同一份字节码, 在内存中只有一份 */ System.out.println(cla1 == cla2 ); System.out.println(cla2 == cla3); /* * 判断,一个类型是否是基本类型. 基本类型有9个: 8个基本类型+void. * int long short float double char byte boolean */ //String 不是基本类型 System.out.println(str.getClass().isPrimitive()); //int 是基本类型 System.out.println(int.class.isPrimitive()); //Integer 不是基本类型 System.out.println(Integer.class.isPrimitive()); //int 和 Integer 是不同的类型, 他们在内存中的字节码是不同的 System.out.println(int.class == Integer.class); //Integer.Type方法返回的是基本类型int的字节码 System.out.println(Integer.TYPE == int.class); //数组也是一个Class对象 //int[]数组不是基本类型 System.out.println(int[].class.isPrimitive()); //int[] 数组是数组么? 是的 System.out.println(int[].class.isArray());
//获得String这个类的所有个构造方法 Constructor<?>[] cons = String.class.getConstructors(); //获得String的指定构造方法: String(StringBuffer s){} //下面表示只接受一个参数StringBuffer类型的构造方法 Constructor<?> con = String.class.getConstructor(StringBuffer.class); //将构造方法实例化 Object o = con.newInstance(new StringBuffer("abc")); System.out.println(o);
我记得 之前说过, 得到Class类以后, 可以调用Class.newInstances()
/* * 实例化 */ Class cla4 = Class.forName("java.lang.String"); //我们可以直接使用Class的newInstance()方法. 但注意这个方法是无参的构造方法. Object o4 = cla4.newInstance(); /* * 如果调用一个类的有参构造方法呢? * 使用构造器. 如下操作, 就是调用了含有一个StringBuffer类型参数的构造方法 * 这样调用的就是有参的构造方法 */ Constructor<?> con4 = cla4.getConstructor(StringBuffer.class); Object o44 = con4.newInstance(new StringBuffer("aaa")); System.out.println(o44);
public class RefelectPoint { private int x; public int y; public RefelectPoint(int x, int y){ this.x = x; this.y =y; } }
下面的代码在main方法中执行
/** * 字段 * 如何获取共有字段 */ RefelectPoint rp = new RefelectPoint(4,6); //现在我要通过反射获取rp对象中的x字段的值和y字段的值 Field fieldy = rp.getClass().getField("y"); /* * 注意: 这里的fieldx表示的是字段, 他不代表任何值. 因为RefelectPoint有很多歌对象, * fieldx仅表示这些对象中的指定字段. 那到底是哪个对象的值呢? 也就是如何获取这个值呢? * * 注意, 使用这种方法只能获得public域的参数 */ System.out.println(fieldy.get(rp));
/* * 那如何获取private类型的参数呢 * 如果直接获取会报告异常: java.lang.NoSuchFieldException: x * * 我们可以通过对象的getDeclareField("x")来获取. * 这个时候, 我们调用这个方法, 返回的依然是一个异常 :modifiers "private" * 这时我们要调用setAccessible(true)强制通知,告诉编译器我可以获取这个私有属性 */ Field fieldx = rp.getClass().getDeclaredField("x"); fieldx.setAccessible(true); System.out.println(fieldx.get(rp));
练习: 将一个对象中的所有String类型的成员变量的值中的b改成a
/** * 将一个对象中的所有String类型的成员变量的值中的b改成a * 思路: * 1. 获取所有的String类型的成员 * 2. 获取成员对应的值 * 3. 通过正则表达式或者replaceAll方法对字符串进行替换 */ Class cla5 = RefelectPoint.class; Constructor<?> cons5 = cla5.getConstructor(int.class, int.class); Object o5 = cons5.newInstance(5, 10); Field[] f5s = cla5.getFields(); for(Field f5: f5s){ //获取Field的类型 Class<?> t5 = f5.getType(); //判断是否是String类型,只需看他的字节码是否是同一份就可以了. if(t5 == String.class){ String v5 = (String) f5.get(o5); v5 = v5.replaceAll("b", "a"); f5.set(o5, v5); System.out.println(v5); } }
运行结果:
aall aasketaall itcas
/** * 方法反射 */ String str1 = "abc"; //第一步:通过反射调用指定方法 Method method = String.class.getMethod("charAt", int.class); //第二步: 执行方法 char c = (char) method.invoke(str1, 2); System.out.println(c);
通过反射调用getMethod()方法,在执行invoke方法即可。 如果想获取所有的方法, 可以使用getMethods()方法。