------- android培训、java培训、期待与您交流! ----------
- import语句可以导入一个类或某个包中的所有类
- import static语句导入一个类中的某个静态成员或所有静态成员
package cn.itcast.day01;
import static java.lang.Math.*;
import cn.itcast.day02.AnnotationTest;
public class StaticImport {
public static void main(String[] args) {
//静态成员如max() abs()等静态函数可直接使用,使代码简洁
System.out.println(max(2, 3));
System.out.println(abs(3 - 6));
//静态成员如PI等静态字段可直接使用,使代码简洁
System.out.println(PI);
}
}
为此引入了可变参数,其特点是:System.out.println(countScore(2,3,5)); System.out.println(countScore(1,2,3,5));
- 只能出现在参数列表的最后,这个要记住;
- ... 位于变量类型和变量名之间,前后有无空格都可以;
- 调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参。
package cn.itcast.day01; public class VariableParameter { public static void main(String[] args) { int sum = add(2); System.out.println(sum); } public static int add(int x, int... args) {//可变参数的使用 System.out.println(args.length); int sum = x; for (int arg : args) {//下面要说的增强For循环 sum += arg; } return sum; } }
- 迭代变量必须在( )中定义!
- 集合变量可以是数组或实现了Iterable接口的集合类(java有这样的限制是因为增强for循环内部是使用迭代器实现的)
- 在使用增强for循环时,不能为元素进行赋值操作。
public static int add(int x,int ...args) { int sum = x; for(int arg:args) { sum += arg; } return sum; }
增强for循环迭代数组
注意:不能对元素进行赋值操作String [] arr = {"a", "b", "c"}; //数组的静态定义方式,只试用于数组首次定义的时候 // 传统方式 for(int i=0; i<arr.length; i++) { // i依次表示数组的角标 String s = arr[i]; System.out.println(s); } System.out.println("-------------------------------------"); // 在jdk5中我们可以使用增强for循环迭代 // 增强for循环括号里写两个参数,第一个是声明一个变量,变量类型必须是数组元素的类型 // 第二个就是需要迭代的容器 // for循环会循环容器的length次, 每次都将容器的第n-1个元素赋值给声明的变量 for(String s : arr) { // 循环体, 执行arr.length // 每次都将arr中的第n-1个元素给s System.out.println(s); // }
四、基本数据类型的自动拆箱与装箱//在使用增强for循环时,不能对元素进行赋值 int[] arr = {1,2,3}; for(int num : arr) { num = 0; } System.out.println(arr[1]);//结果是2,不是0
为编程带来了很多的好处:之前容器类只能持有引用数据类型,不能持有基本类型,有了自动装箱与拆箱机制,语法上容器类依然不能持有基本数据类型,但看起来可以持有了。
List<Integer> list = new ArrayList<Integer>();
list.add(5);//自动装箱,这样容器看上去可以持有基本数据类型了
为了优化,虚拟机为包装类提供了缓冲池, Integer池的大小 -128~127 一个字节的大小Integer num1 = 12; //自动装箱
System.out.println(num1 + 12); //自动拆箱
扩展:java为了优化字符串的操作,提供了String常量池:Integer num1 = 12; Integer num2 = 12; System.out.println(num1 == num2);//true,在缓冲池中共享——>享元设计模式 Integer num3 = 129; Integer num4 = 129; System.out.println(num3 == num4);//false,因为是对象 Integer num5 = Integer.valueOf(12); Integer num6 = Integer.valueOf(12); System.out.println(num5 == num6);//true,
五、枚举:Java为了优化字符串操作 提供了一个缓冲池 面试题: String s = “abc” 和 String s = new String(“abc”) 的区别 String s = new String(“abc”) 创建了几个对象 String s = “a” + “b” + “c” + “d” 创建了几个对象 String s1 = “a” String s2 = “b” String s3 = s1 + s2; s3==”ab”? /*1. String s = "abc", 虚拟机首先会检查String池里有没有"abc"对象(通过equals方法) // 如果有,直接返回引用,如果没有,会在池里创建一个“abc”对象,并返回引用 String s1 = "abc"; String s2 = "abc"; System.out.println(s1==s2); // result: true */ /* 2. String str = new String("abc"); 两个或一个,”xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”不管出现多少遍,都是缓冲区中的那 一个。New String每写一遍,就创建一个新的对象,它一句那个常量”xyz”对象的内容来创建出一个新String对象。如 果以前就用过’xyz’,这句代表就不会创建”xyz”自己了,直接从缓冲区拿。 不管缓冲池是否有"abc", 都会在堆内存创建一个"abc"对象,返回引用 同时也会对String池进行检查,如果String池中没有“abc”的话,也会在常量池中创建一个“abc”对象的 // 此时,负责检查并维护缓冲池,其实堆内存的对象是缓冲池中"abc"对象的一个拷贝 String s1 = new String("abc"); String s2 = new String("abc"); System.out.println(s1==s2); // result: false */ /* 3. String s = "a" + "b" + "c" + "d"; java编译器有个合并已知量的优化功能 // 在编译阶段就把"a" + "b" + "c" + "d" 合并为 ”abcd“ String s = "a" + "b" + "c" + "d"; //String s = "abcd"; System.out.println(s=="abcd");// result: true */ /* 4. String s1 = "a"; String s2 = "b"; String s3 = s1 + s2; // String是常量,不能相加的,java如何实现的? StringBuilder sb = new StringBuidler(s1); sb.append(s2); s3 = sb.toString(); 也就是说实际上s3是方法返回的String对象 凡是方法返回的字符串对象都是在堆内存的 */
JDK1.5引入了新的类型——枚举。在 Java 中它虽然算个“小”功能,却给我的开发带来了“大”方便。
为什么要使用枚举:
- 枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。
- 枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。
- 私有的构造方法
- 每个元素分别用一个公有的静态成员变量表示
- 可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类
package cn.itcast.day01; public abstract class WeekDay { private WeekDay() {};//私有的构造方法 public static final WeekDay SUN = new WeekDay() {//每个元素分别用一个公有的静态成员变量表示
@Override public WeekDay nextDay() { return MON; } }; public static final WeekDay MON = new WeekDay() { @Override public WeekDay nextDay() { return TUE; } }; public static final WeekDay TUE = new WeekDay() { @Override public WeekDay nextDay() { return WED; } }; public static final WeekDay WED = new WeekDay() { @Override public WeekDay nextDay() { return THU; } }; public static final WeekDay THU = new WeekDay() { @Override public WeekDay nextDay() { return FRI; } }; public static final WeekDay FRI = new WeekDay() { @Override public WeekDay nextDay() { return SAT; } }; public static final WeekDay SAT = new WeekDay() { @Override public WeekDay nextDay() { return SUN; } }; public abstract WeekDay nextDay(); //可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类 /*public WeekDay nextDay(){ if(this == SUN) return MON; else if(this == MON) return TUE; else if(this == TUE) return WED; else if(this == WED) return THU; else if(this == THU) return FRI; else if(this == FRI) return SAT; else if(this == SAT) return SUN; return null; }*/ @Override public String toString() { return "WeekDay []"; } }
用法一:常量public enum TrafficLamp{ RED(45) { @Override public TrafficLamp nextLamp() { return GREEN; } },GREEN(30) { @Override public TrafficLamp nextLamp() { return YELLOW; } },YELLOW(30) { @Override public TrafficLamp nextLamp() { return RED; } }; private int time; private TrafficLamp(int time) { this.time = time; }; public abstract TrafficLamp nextLamp(); }
public enum Color{
red, green, blue, yellow
}
用法三:向枚举中添加新方法enum Signal { GREEN, YELLOW, RED } public class TrafficLight { Signal color = Signal.RED; public void change() { switch (color) { case RED: color = Signal.GREEN; break; case YELLOW: color = Signal.RED; break; case GREEN: color = Signal.YELLOW; break; } } }
如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例。
public enum Color { RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4); // 成员变量 private String name; private int index; // 构造方法 private Color(String name, int index) { this.name = name; this.index = index; } // 普通方法 public static String getName(int index) { for (Color c : Color.values()) { if (c.getIndex() == index) { return c.name; } } return null; } // get set 方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } }
用法四:覆盖枚举的方法
下面给出一个toString()方法覆盖的例子。
public enum Color { RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4); // 成员变量 private String name; private int index; // 构造方法 private Color(String name, int index) { this.name = name; this.index = index; } //覆盖方法 @Override public String toString() { return this.index+"_"+this.name; } }
用法五:实现接口
所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。
用法六:使用接口组织枚举public interface Behaviour { void print(); String getInfo(); } public enum Color implements Behaviour{ RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4); // 成员变量 private String name; private int index; // 构造方法 private Color(String name, int index) { this.name = name; this.index = index; } //接口方法 @Override public String getInfo() { return this.name; } //接口方法 @Override public void print() { System.out.println(this.index+":"+this.name); } }
public interface Food { enum Coffee implements Food{ BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO } enum Dessert implements Food{ FRUIT, CAKE, GELATO } }
用法七:关于枚举集合的使用
java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的key是enum类型,而value则可以是任意类型。关于这个两个集合的使用就不在这里赘述,可以参考JDK文档。
关于枚举的实现细节和原理请参考:
用法八:单例设计的另一种方式
当枚举中只有一个元素时,可以作为单例的一种实现方式。