1、特性一:静态导入
概念:静态导入用于简化程序对类静态属性和方法的调用
语法:Import static 包名.类名.静态属性|静态方法|*
例如:
(1)import static java.lang.System.out (2)Import static java.lang.Math.* |
例:
package com.itheima.reflect; import static java.util.Arrays.*;//静态导入 public class EnumTest { public static void main(String[] args) { int []arr={3,9,4,1,10};//创建一个整型数组 sort(arr);//调用Arrays中的sort方法进行对数组排序 for(int i=0;i<arr.length;i++){//打印数组 System.out.print(arr[i]+","); } } } |
静态导入在实际的开发中用的不多
2、特性二:自动装箱和拆箱
概念:
(1)自动装箱:指开发人员可以把一个基本数据类型直接赋给对应的包装类
(2)自动拆箱:指开发人员可以把一个包装类对象直接赋给对应的基本数据类型
例:
Integer i=1;//装箱 int j=i;//拆箱 |
从上面的两句代码可以看出,JVM一个小小的改动,该我们编程人员带来了极大的便利。下面一个典型的应用来说明:
package com.itheima.reflect; import java.util.ArrayList; import java.util.List; public class EnumTest { public static void main(String[] args) { List list=new ArrayList(); //我们知道list的add方法接受的参数是Object,而此时我们可以直接加入整型的数值,这就是自动装箱 list.add(1); list.add(2); //在JDK1.4之前,我们不能像上面那样,否则会报错,需如下写 list.add(new Integer(1)); list.add(new Integer(2)); } } |
从上面的应用中我们可以看出自动装箱和拆箱的好处
3、特性三:增强for循环
(1)作用:取出集合或者数组的数据
(2)引入增强for循环的原因:在JDK1.5之前的版本中,遍历数组或者集合中的元素需要先获得数组的长度或者集合的迭代器,比较麻烦,所以引入了增强for循环。
(3)语法格式:
for(变量类型 变量:需要迭代的数组或者集合){ } |
注意:增强for循环只能用在数组或者实现Iterator接口的集合类上。
例:
@Test public void test(){//对数组利用增强for循环 int[]arr={1,3,5};//创建一个整数型的数组 for(int a:arr){//利用增强for循环打印数组中元素 System.out.print(a+","); } } @Test public void test1(){//对集合利用增强for循环 List<String>list=new ArrayList<String>();//创建一个list集合 list.add("黑马_1");//向集合中添加元素 list.add("黑马_2");//向集合中添加元素 list.add("黑马_3");//向集合中添加元素 list.add("黑马_4");//向集合中添加元素 for(String str:list){//利用增强for循环打印集合中的元素 System.out.println(str); } } |
例:Map中的增强for循环
因为Map中不存在Iterator接口,不能直接使用增强for循环,需要将其转换成set后在利用for循环
方法一:利用map中的keySet获得Set集合
@Test public void test3(){ Map<String,String>map=new LinkedHashMap<String,String>();//创建一个map集合 map.put("1","黑马_1");//向集合中添加元素 map.put("2","黑马_2");//向集合中添加元素 map.put("3","黑马_3");//向集合中添加元素 map.put("4","黑马_4");//向集合中添加元素 //调用map中的keySet获取一个set集合 for(String st:map.keySet()){ String key=st;//获取键 String value=map.get(st);//获取键 System.out.println(key+":"+value); } } |
运行结果:
1:黑马_1
2:黑马_2
3:黑马_3
4:黑马_4
方法二:利用map中的entrySet方法获得Set集合
@Test public void test4(){//创建一个map集合 Map<String,String>map=new LinkedHashMap<String,String>();map.put("1","黑马_1");//向集合中添加元素 map.put("2","黑马_2");//向集合中添加元素 map.put("3","黑马_3");//向集合中添加元素 map.put("4","黑马_4");//向集合中添加元素 //调用map中的entrySet()获取一个set集合 for( Map.Entry<String,String>entry:map.entrySet()){ String key=entry.getKey();//获取键 String value=entry.getValue();//获取值 System.out.println(key+":"+value); } } |
运行结果:
1:黑马_1
2:黑马_2
3:黑马_3
4:黑马_4
增强for循环需要注意的问题
@Test public void test2(){ List<String>list=new ArrayList<String>();//创建一个list集合 list.add("黑马_1");//向集合中添加元素 list.add("黑马_2");//向集合中添加元素 list.add("黑马_3");//向集合中添加元素 list.add("黑马_4");//向集合中添加元素 for(String str:list){//利用增强for循环打印集合中的元素 str="黑马程序员"; } System.out.println(list.get(3)); } |
上面的运行结果是:黑马_4,为什么不是黑马程序员呢?
解决这个问题需要了解增强for循环的一个特点了:增强for循环只适合取数据。上面str以前指向集合中的元素,现在指向了“黑马程序员”,但是集合中的元素并没有发生改变,所以运行结果是黑马_4.
4、特性四:可变参数
问题:在JDK1.4之前,例如几个数相加的方法,而相加方法的参数并不确定,我们怎么办呢?
我们知道,java支持重载,就是方法名相同,参数列表不相同,如:
//传两个参数相加 Add(1,3); //四个参数相加 Add(1,3,5,6); |
如果有多个参数相加,需要重载add方法,这样非常的麻烦,到JDK1.5之后,可以利用可变参数的方式来解决这个问题
例:
package com.itheima; import org.junit.Test; public class Test3 { public void add(int...num){//可变参数的方法 int sum=0; for(int i:num){//利用增强for循环来进行对可变参数遍历 sum+=i;//相加求和 } System.out.println("sum="+sum); } @Test public void test1(){ add(1,2,3);//传三个参数 add(1,3);//传两个参数 } } |
运行结果:6,4
注意事项:
(1)调用可变参数的方法时,编译器将自动创建一个数组保存传递给方法的可变参数,因此,程序员可以再方法中以数组的形式访问可变参数 (2)可变参数只能处于参数列表的最后,所以一个方法最多只能有一个长度可变的参数。 |
例:测试JDK中具有可变参数的类Arrays.asList()方法。分别传多个参数,传数组
(1)传多个参数的情况
@Test public void test2(){ List<String>list=Arrays.asList("黑马_1","黑马_2","黑马_3");//传多个参数的情况 System.out.println(list);//打印集合 } |
运行结果:[黑马_1, 黑马_2, 黑马_3]
从结果可以看出:验证了第一个注意事项中所说的情况:调用可变参数的方法时,编译器自动创建一个数组保存可变参数。
(2)传数组的情况
@Test public void test3(){ String[]str={"黑马_1","黑马_2","黑马_3"}; List<String>list=Arrays.asList(str);//传数组的情况 System.out.println(list);//打印集合 } |
运行结果:[黑马_1, 黑马_2, 黑马_3]
但是下面的程序会出现什么情况呢?
@Test public void test4(){ int[]arr={1,2,3}; List list=Arrays.asList(arr);//传数组的情况 System.out.println(list);//打印集合 } |
运行结果:[[I@1362012]
问什么出现这个结果呢?我们明明在上次实验中就可以,就是把数组类型改一下而已。
从Arrays.asList(T...a)方法中我们可以看出,此方法的可变参数要的是一个对象,前面传一个一个的String对象是没有问题的,但是此程序传的是一个整数型的数组,它就会把数组当成一个对象往里面放。但是把int改成Integer就会得出想要的结果了。
5、特性五:枚举
(1)为什么需要枚举
一些方法在运行时,它需要的数据不能是任意的,而是必须是一定范围内的值,此类问题在JDK以前采用自定义带有枚举功能的类解决,JDK1.5以后可以使用枚举来解决这个问题了。
(2)枚举的特性
(1)枚举类也是一种特殊形式的java类 (2)枚举类中声明的每一个枚举值代表枚举类的一个实例对象 (3)与java的普通类一样,在声明枚举类时,也可以声明属性、方法和构造函数,但是枚举类的构造函数必须为私有的 (4)枚举类也可以实现接口或继承抽象类 (5)JDK1.5扩展了switch语句,它除了可以接收int,byte,char,short外,还可以接收一个枚举类型 (6)若枚举类只有一个枚举值,则可以当作单态设计模式使用 |
例:在JDK1.5之前的枚举形式
//模拟一个枚举类 class Grade{ //首先需要把此类的构造函数私有化 private Grade(){} //提供一些对象 public static final Grade A=new Grade(); public static final Grade B=new Grade(); public static final Grade C=new Grade(); public static final Grade D=new Grade(); public static final Grade E=new Grade(); } |
在JDK1.5以后可以使用枚举了
//定义一个枚举 enum Grade{ A,B,C,D,E; } |
例:让枚举有字段、构造函数和方法
//定义一个枚举 enum Grade{ A,B,C,D,E; private String value; private Grade(String value){ this.value=value; } public String getValue(){ return this.value; } } |
上面的程序编译失败,为什么呢?
我们从程序中可以看到,我们定义了有参的构造函数,而我们在定义五个对象时,并没有给它们传参,所以错误,改正如下:
package com.itheima.enumeration; import org.junit.Test; public class EnumDemo { //定义一个方法用于打印 public void print(Grade g){ System.out.println(g.getValue()); } @Test public void test1(){ print(Grade.A); } } //定义一个枚举 enum Grade{ A("100-90"),B("90-80"),C("80-70"),D("70-60"),E("59-0"); private String value;//定义一个字段 private Grade(String value){//把枚举的构造方法私有化 this.value=value; } public String getValue(){//定义一个方法 return this.value; } } |
运行结果:100-90
(3)带抽象方法的枚举
例:我们想把上面的A,B、C、D、E改成我们中国的习惯优,良、中等、及格、不及格
package com.itheima.enumeration; import org.junit.Test; public class EnumDemo { //定义一个方法用于打印 public void print(Grade g){ System.out.println(g.localValue()); } @Test public void test1(){ print(Grade.A); } } //定义一个枚举 enum Grade{ A("100-90"){//因为在对象实例化时,必须实现了抽象方法 @Override public String localValue() { return "优"; } } ,B("90-80"){//因为在对象实例化时,必须实现了抽象方法 @Override public String localValue() { return "良"; } } ,C("80-70"){//因为在对象实例化时,必须实现了抽象方法 @Override public String localValue() { return "中等"; } } ,D("70-60"){//因为在对象实例化时,必须实现了抽象方法 @Override public String localValue() { return "及格"; } } ,E("59-0"){//因为在对象实例化时,必须实现了抽象方法 @Override public String localValue() { return "不及格"; } }; private String value;//定义一个字段 private Grade(String value){//把枚举的构造方法私有化 this.value=value; } public String getValue(){//定义一个方法 return this.value; } //因为不知道返回是什么,所以定义成抽象方法 public abstract String localValue(); } |
从上面的例子中我们可以看出,如果枚举中有抽象方法的时候,我们在创建对象的时候必须实现这些抽象方法,否则会报错。
(4)Enum类
Java中声明的枚举类均是Enum的子类
一些重要的方法如下:
(1)public final String name():返回此枚举常量的名称,在其枚举声明中对其进行声明。 (2)public final int ordinal():返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。 (3)public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name):返回带指定名称的指定枚举类型的枚举常量 (4)Values():此方法在JDK文档中查找不到,但是每一个枚举类都有该方法,它用于遍历枚举的所有枚举值 |
练习:编写一个关于星期几的枚举WeekDay,要求:
枚举值:MON,TUE,WED,THU,FRI,SAT,SUN
该枚举要有一个方法,调用该方法返回中文格式的星期。
package com.itheima.enumeration; import org.junit.Test; public class EnumDemo2 { public void print(WeekDay wd){//调用枚举中的localWeek()方法 System.out.println(wd.localWeek()); } @Test public void test(){//测试 print(WeekDay.FRI); } } enum WeekDay{ MON{//MON实例要实枚举中现抽象的方法 @Override public String localWeek() { return "星期一"; } }, TUE{//TUE实例要实枚举中现抽象的方法 @Override public String localWeek() { return "星期二"; } }, WED{//WED实例要实枚举中现抽象的方法 @Override public String localWeek() { return "星期三"; } }, THU{//THU实例要实枚举中现抽象的方法 @Override public String localWeek() { return "星期四"; } }, FRI{//FRI实例要实枚举中现抽象的方法 @Override public String localWeek() { return "星期五"; } }, SAT{//SAT实例要实枚举中现抽象的方法 @Override public String localWeek() { return "星期六"; } }, SUN{//SUN实例要实枚举中现抽象的方法 @Override public String localWeek() { return "星期日"; } }; //把枚举的构造函数私有化 private WeekDay(){} //第二步:向外公开一个方法,因为不知道具体星期几,用抽象 public abstract String localWeek(); } |