java JDK1.5新特性(一) [静态导入] [可变参数] [增强for] [自动装箱拆箱] [枚举]

 


  1. 静态导入 Static import
    1. 静态导入的优缺点
  2. 可变参数 Varargs
    1. 可变参数的特点
    2. 方法使用可变参数重载
    3. 新特性的可变参数与旧版本的数组参数的兼容性
  3. 增强for循环 forEnhance
    1. 增强for循环格式
    2. 增强for循环的优缺点
    3. 三种遍历方式
  4. 自动装箱autoboxing拆箱unboxing  
    1. 享元设计模式
  5. 枚举Enums
    1. 枚举类的特点 
    2. 枚举类
    3. Enum 类 


  • 静态导入(Static import)


import static 包名.类名.*

类名后可以是通配符也可以是成员或静态方法名,字段,静态变量名



如通过

import static java.lang.Math.*;

则可以直接使用Math类下的方法或字段静态变量而不需要每次调用都要在前面加Math.来调用

静态导入的优缺点:

优点:

对某类进行静态导入之后,可以不需要每次调用该类静态方法或者字段静态属性时都要带上类名

在多次使用某个类的静态方法或字段时,可以简化输入操作

缺点:

阅读性变差 

当不同的类有相同的静态方法名或字段名时若同时进行静态导入使用时会出现混淆 , 例如

如果对Integer类和Long类执行了静态导入,引用MAX_VALUE将导致一个编译器错误,

因为Integer和Long都有一个MAX_VALUE常量,并且Java不会知道你在引用哪个MAX_VALUE。



  • 可变参数(Varargs)


泛型是可变参数类型 而这里的可变参数是指可变参数个数


        可变参数的特点:

    • 一个方法只能有一个可变参数,并且这个可变参数必须出现在参数列表的最后  " 类型...args"

args为参数数组名,调用可变参数的方法时,编译器为可变参数隐含创建一个数组,在方法体中以数组形式访问可变参数

调用的时候可以指定任意个指定类型的参数,参数被存入名为args的数组中,方法体中可以对该数组进行操作







普通办法的"可变参数"



public class PrintArgs1 {
       static void printArray(Object[] args){
              for(Object obj:args)
                     System.out.print(obj+" ");
              System.out.println();
       }
 
       public static void main(String[] args){
              printArray(new Object[]{
                     new Integer(47),new Float(2.3),new Double(12.34)  
              });
	   }
}




JDK1.5的可变参数

public class PrintArgs2 {
       static void printArray(Object...args){
              for(Object obj:args)
                     System.out.print(obj+" ");
              System.out.println();
       }
 
       public static void main(String[] args){
              printArray(new Integer(47),new Float(3.14),new Double(11.11));
              printArray(new A(),new A(),new A());
              printArray();
       }
}



VarArgs1和VarArgs2的 printArray方法体都一样 , 但是
前者: 参数必须指明接收的参数类型为Object类或子类对象的数组 , 数组长度不定,可以在调用的时候确定,
而且在调用的时候就必须创建一个Object类数组对象 , 用创建的数组对象接收要操作的数据 , 再将
该数组传给调用函数
后者: 在参数列表中没有指明接收的是Object数组,只指明接收的是哪一类 , 但是调用的时候会自动产生一个
Object类数组进行接收参数,参数个数可以在调用时确定,




        

方法使用可变参数重载

        方法重载中使用参数列表使用可变参数时,那么调用时会自动匹配一个最佳方法进行调用;
重载中多个方法都匹配时优先使用定长参数的方法;

重载中不能同时存在如下形式

public void method1(Object... arg1){};  

public void method1(Object[] arg1){};

两种形式被认为是重复的 , 可以看出前者调用的时候跟后者一样,只不过后者是认为创建数组,前者是自动产生的

public void method1(Object... arg1){};

等效于  

public void method1(T... arg1){};  



以下重载方法

0) static void printArray(Integer q,Integer t){}

1) static void method(Byte...args){}

2) static void method(Short...args){}

3) static void method(Character...args){}

4) static void method(Integer...args){}

5) static void method(Long...args){}

6) static void method(Float...args){}

7) static void method(Double...args){}

8) static void method(String...args){}

9) static void method(Object...args){}static void method(T...args){}



对重载方法的调用

method(12,42);//调用0)的method

method(12,42,44,77);//调用4)的method

method(42,244444234,423432424);//调用4)的method

method(42L,244444234L,423432424L);//调用5)的method

method(23,123,0);//调用4)的method

method((byte)23,(byte)123,(byte)0);//调用1)的method

method("安","fe","和");//调用8)的method

method('v','a','4','a');//调用3)的method

method(2.4,5,'f',"fe");//调用9)的method

method(2.4,5,'f',"fe",new Object());//调用9)的method



整型参数如果没有强制转换则默认匹配的只有Integer类型的方法或Object类型或泛型方法 , 

但同时存在时优先调用Integer类的参数的方法 

字符串型实参只匹配String类变长参数方法或Object类或泛型,同时存在是只会调用String类参数方法

字符型也一样优先调用Character类参数方法


新特性的可变参数与旧版本的数组参数的兼容性



        将一个数组的实际参数传递给一个在

JDK1.5以前属于数组构成的形式参数

JDK1.5后属于可变参数的形式参数的方法时

对于能兼容JDK1.5以前方式的会直接用以前的方式接受参数

对于不能兼容的以前方式的会用JDK1.5出现的可变参数方式将传入的

数组解包,将每个数组元素传给可变参数

int[] i = {1,3,5};

Integer[] j = {1,3,5};

String[] sts = {"f","fe","fee"};

/*传入int数组,因为int不是引用类,只有int[]才是引用类,数组中的int元素

不能当做集合的元素存入到集合中,即不兼容旧的数组形式的版本,

不能按照数组方式传入,只能按可变参数的一个参数传入,所以返回的集

合中只有一个元素,即数组引用i本身*/

System.out.println(Arrays.asList(i));

/*Integer数组元素是引用类型可以被集合接收,所以j被当做数组传入,

传入时,将拆散数组元素将元素装入集合*/

System.out.println(Arrays.asList(j));


/*传入的String数组,因为String就是Object类,所以传入的数组参数被

拆开,兼容旧版本按照数组参数方式来处理 , 所以返回的集合中存入被打散

的String数组的元素*/

System.out.println(Arrays.asList(sts));

System.out.println(Arrays.asList(1,3,5));//按可变参数传入

System.out.println(Arrays.asList("f","fe","fee"));//按可变参数传入

System.out.println("["+Arrays.asList(i).get(0)[0]+", "+

Arrays.asList(i).get(0)[1]+", "+

Arrays.asList(i).get(0)[2]+"]");

打印结果为   

[[I@1cf8583]

[2, 4, 6]

[f, fe, fee]

[1, 3, 5]

[f, fe, fee]

[1, 3, 5]






  • 增强for循环 forEnhance

增强for循环格式

for(Type 变量名 : 该类型的数组\集合容器){...}

集合容器可以是数组或实现了Iterable接口的集合


增强for循环的优缺点

优点: 与传统for循环比较大大简化了代码

缺点: 不能根据数组或有序集合元素索引来操作元素


三种遍历方式

1 普通for遍历           

2 增强型for遍历

for(元素类型 元素变量:集合/数组)

2.1--遍历数组

int [] arr ={1,3,5,6};
for(int i:arr){...}
int[][] arrs = {{1,4,7},{2,6,7,4}};
for(int[] r : arrs)
{
for(int e:r)
{
...
}
...
}

2.2---遍历集合

增强型for循环优点主要表现在集合的遍历上,利用了集合的泛型特性

局限性:

不能利用数组或有序集合的索引的进行判断删除元素等操作,

不能对集合本身进行操作

底层原理还是迭代器 如:

ArrayList list = new ArrayList();  

for (Integer i : list) { ... }

实际是以下for的简化写法

ArrayList list = new ArrayList();

for (Iterator  i = list.iterator(); i.hasNext();) {

Integer value=i.next();

}

3, 迭代遍历

                       迭代法是集合提供的一种遍历方法,适用于任何一个类

Set set = new HashSet();
Iterator it = set.iterator(); 
while (it.hasNext()) 
{  
String str = it.next();  
System.out.println(str); 
}



自定义实现了Iteratle接口的类 , 使该类能用增强for来遍历


import java.util.Iterator;


public class Container implements Iterable {
	protected T[] elements;
	public Container(T... elems) {
		this.elements=elems;
	}
	public Iterator iterator() {//实现Iterable接口下的 iterator方法
		return new Iterator(){//匿名内部类实现 Iterator 接口覆盖三个方法
			private int index = elements.length-1;
			public boolean hasNext() {
				return index > -1;
			}


			public T next() {
				return elements[index--];
			}
			
			public void remove() {
				throw new UnsupportedOperationException();
			}
		};
	}
	
	public static void main(String[] args)
	{
		Container c = new Container("2","3","4",74);
		for(Object i:c)
		{
			System.out.println(i);
		}
	}
}
 
   












  • 自动装箱(autoboxing)、拆箱(unboxing)  



自动装箱拆箱是基本数据类型与包装类之间自动进行封装和拆解


常规方法装箱拆箱

int i = 100;

Integer i1 = new Integer(i);//装箱

int i2 = i1.intValue();//拆箱



采用自动装箱

Integer i1 = 100 ;//自动装箱

int i2 = i1;//自动拆箱

享元设计模式


即\通过自动装箱包装的数据不大于127 的一个字节之内存放在常量池中



在使用的时候如果该数在不大于127的一个字节范围内则只要常量池中已经存在该数,那么就可以直接使用

而不需要在堆内存中创建新对象,但如果常量池中没有该数则需要在常量池中创建一个

通过基本数据类型包装的类的静态方法 valueOf来包装基本数据时,跟自动装箱一样

在不大于127范围内时数据都存放在常量池中且最多只有一份



八种基本类型的包装类和对象池 

java中基本类型的包装类的大部分都实现了常量池技术,这些类是 Byte,Short,Integer,Long,Character,Boolean,

另外两种浮点数类型的包装类则没有实现 , 另外 Byte,Short,Integer,Long,Character 这5种整型的包装类也只是在

对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。



因为这些数据会经常使用所以不必要每次使用的时候都为他们开辟内存空间创建对象

26个英文字母属于 char 类型 被Character 包装之后在 小于等于127范围内的字符都实现了常量池技术






  • 枚举(Enums)



JDK1.5加入了一个全新类型的“类”-枚举类型

在“枚举”类型的定义中列举出所有可能的取值,被说明为该“枚举”类型的变量取值不能超过定义的范围。



  • 枚举类的特点 

  • 枚举类是一种特殊的类,每个元素都是该类的static final成员
  • 枚举类型不仅可以定义枚举值,它还可以定义构造函数,方法以及属性字段; 
  • 枚举的构造方法必须是私有的 , 不写权限修饰符的话也是私有的,只能在内部使用,

构造方法定义在枚举列表之后 , 当定义了构造方法之后,为了明确枚举常量创建时是调用哪个

构造方法的,会在常量名之后跟小括号括号中指明所调用指定参数列表的构造方法

  • 枚举类型允许有抽象函数 , 当枚举类内定义有抽象方法时,该枚举类就 成了抽象类,所以枚举的成员

是通过该抽象的枚举类的实现子类创建的,一般其实现子类被定义为抽象枚举类的匿名内部类

该匿名内部类是枚举类的实现子类,紧跟在枚举元素后, 枚举常量就是通过这个匿名内部类来创建的

被声明为枚举类的常量引用指向了匿名内部实现子类创建的对象,

  • 枚举可以在switch 中使用
  • 枚举可以单独定义 , 也可以定义在其他类内 , 作为内部类使用,单独定义时访问修饰符只能有public或默认

              枚举定义为内部类时,可以有四种访问权限 , 可以在一个类内定义多个枚举类,访问权限可以都是public

  • 枚举类

枚举类 用关键字 enum 声明的类隐性继承了 Enum 类

枚举常量 , 就是该枚举类型的实例(静态)如:



public enum WeekDay{
		SUN,MON,TUE,WED,THI,FRI,SAT
	}


public enum Month {  
JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC
}


public enum TrafficLight{
	RED,GREEN,YELLOW
}



关键词 enum 声明了 TrafficLight 是一个枚举类 ,他隐性直接继承 Enum 类 
并有一个由编译器添加的构造函数,该构造函数可以调用 Enum 类的构造函数
Enum 有个受保护构造函数 可以接收两个参数 ,分别是此枚举常量的名称 ,枚
举常量的序数(在枚举声明中的位置)程序员无法调用只能是内部自动完成调用的 , 
同时该枚举类也隐式被声明为 static final 类 故枚举类是不能继承其他类 也不能
被其他类继承的


RED,GREEN,YELLOW 是该枚举类的三个 static final 成员 , 他们的值就是
values() 和  valueOf(String s) 也是该枚举类的两个静态成员变量 , 是隐式存在
values() 返回枚举常量列表的数组
valueOf(String s)返回将字符串形式的名称对应的枚举值 , 可以通过字符串对象获得成枚举常量 

该枚举类直接从 Enum 类继承来的方法(除了toString方法外,都是final的)有
name()  返回此枚举常量的名称 , 其名称不会随版本的改变而改变。一般建议用toString
ordinal() 返回此枚举常量的序号,该方法不常用
toString()--也是返回此枚举常量名称 , 覆盖了Object类中的方法 , 
equals(Object other) 此枚举常量与指定的对象比较==时返回true
compareTo(E o) 此枚举常量与指定泛型类比较 ,返回此枚举常量与比较枚举常
                               量声明位置序号相减的结果枚举常量只能与相同枚举类型的其
                               他枚举常量进行比较. 若两对象的getClass()和getDeclaringClass()
                               的结果都不相等时,会抛出类型转换异常
hashCode()覆盖Object类的方法 , 跟Object的方法一样 , 仅仅加上final修饰
clone()覆盖Object 类 中的 clone , 调用就会抛出异常 , 表明枚举不支持clone
getDeclaringClass()返回与此枚举常量的枚举类型相对应的 Class 对象 , 该方法源码
public final Class getDeclaringClass() {
Class clazz = getClass();
Class zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? clazz : zuper;
}
若此枚举常量类定义有内部类则
getDeclaringClass()等效于getClass().getSuperclass
否则等效于getClass() 
public static > T valueOf(Class enumType,
                                            String name)

枚举类除了继承 Enum 类外还有一个超类即上帝类 Object 可以调用所有未覆盖的方法

被覆盖的方法中finalize()方法不能调用的 , clone()方法调用会抛出异常,枚举元素不允许克隆





枚举中定义抽象方法,在枚举常量中实现


enum TrafficLight{
		 RED("红灯",30){
		 	public  TrafficLight turnLight(){
		 		System.out.println("45秒后转为黄灯");
		 		return GREEN;
		 		}
		 	},
		 	GREEN("绿灯",45){
		 	public  TrafficLight turnLight(){
				System.out.println("30秒后转为红灯");
		 		return	YELLOW;
		 		}
		 	},
		 	YELLOW("黄灯",5){
		 	public  TrafficLight turnLight(){
		 		System.out.println("10秒后转为绿灯灯");
		 		return	RED;
		 		}
		 	};


		 	private String name = "";
			private int time;
		 	TrafficLight(String name,int time)
		 	{
		 		this.name = name;
				this.time = time;
		 	}
		 	public String getName()
		 	{
		 		return name;
		 	}
			public Integer getTime()
			{
				return time;
			}


		 	public abstract TrafficLight turnLight();
		 }



TrafficLight 枚举的静态成员就是 RED GREEN YELLOW
每个成员跟着的括号的参数列表表示产生该静态成员时调用的对应的参数的构造方法,
因为枚举中定义构造方法,所以产生该枚举静态成员有其子类来实现,将子类以匿名的
形式跟了每个成员后面直接实现了抽象的枚举类,并且在其中创建了静态的枚举常量
每个枚举常量都是TrafficLight的静态成员,他们通过其后的小括号中的参数来指明调用
指定的构造方法


TrafficLight 枚举编译之后生成两部分class文件  其中一份以TrafficLight.class命名
该文件保存了除了枚举常量列表中每个枚举的匿名内部子类内容外的所有代码信息
而每个匿名内部子类分别成为独立的一份,分别命名为
TrafficLight$1.class
TrafficLight$2.class
TrafficLight$3.class
编号就是枚举常量列表对应位置,




  • Enum 类 

所有的枚举类都继承了 Enum 类

Enum 类的java.lang中的类

因为枚举类型已经继承了 Enum类所以不允许再继承其他类 , 但可以实现其他接口



调用 Enum 的方法

public class EnumDemo
{	
	public static void main(String[] args) throws Exception
	{
		TrafficLight tf = TrafficLight.RED;
		/*1)
		name 方法返回枚举常量值名称
		toString 方法返回枚举常量名称
		*/
		System.out.println(tf);//打印RED
		System.out.println(tf.name());//打印RED
		System.out.println(tf.toString());//打印RED
		/*2)
			compareTo 方法比较此枚举与指定对象相对顺序 
			equals	 方法比较此枚举值与指定对象是否相等
		*/
		System.out.println(tf.compareTo(TrafficLight.YELLOW));//打印-2 , RED在YELLOW前两个位置
		System.out.println(tf.equals(TrafficLight.RED));//打印true
		/*3)
		valueOf(String s)	是一个静态方法,返回将字符串形式的名称对应的枚举值 , 
										可以通过字符串对象获得成枚举常量


		static > T valueOf(Class enumType, String name) 
		是其基类 Enum 的静态方法 , 可以根据 某指定的 T 枚举类的class对象及该枚举的
		枚举常量的字符串形式返回该指定的枚举与指定字符串完全一致的枚举常量
		
		values	是一个静态方法,返回枚举常量列表的数组
		*/
		System.out.println(tf.value);//访问静态成员的属性 , 打印红灯
		TrafficLight	tr = TrafficLight.class, "GREEN")
		System.out.println(TrafficLight.valueOf(tr);//打印GREEN


		TrafficLight[] tt = TrafficLight.values();
		for(TrafficLight i:tt)
		System.out.print(i+" ");//打印  RED GREEN YELLOW


}








你可能感兴趣的:(java基础)