欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CoreJava学习心得16

程序员文章站 2022-07-13 21:37:40
...
Java5.0的新特性

自动装箱和自动拆箱

自动封箱和自动拆箱,它实现了简单类型和封装类型的相互转化时,实现了自动转化。

自动封箱解箱只在必要的时候才进行。还有其它选择就用其它的
byte b     -128~127
Byte b     多一个null

简单类型和封装类型之间的差别
封装类可以等于null  ,避免数字得0时的二义性。
Integer i=null;
int ii=i;  (会抛出NullException 异常)
相当于 int ii=i.intValue();
Integer i=1;相当于Integer i=new Integer(1);

在基本数据类型和封装类之间的自动转换
5.0之前
Integer i=new Integer(4);
int  ii= i.intValue();

5.0之后
Integer i=4;
Long l=4.3;

静态引入

静态成员的使用,使用import static 引入静态成员,也就是可以用静态引入是导入包中的某个类的静态成员,在使用时不用再写类名。
很简单的东西,看一个例子:

没有写静态引入

public class Test{
public static void main(String[] args){
Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
}
}

写了静态引入
import static java.lang.Math.*;
public class Test{
public static void main(String[] args){
System.out.println(sqrt(pow(x, 2) + pow(y, 2)));
}
}

其中import static java.lang.Math.*;就是静态导入的语法,它的意思是导入Math类中的所有static方法和属性。这样我们在使用这些方法和属性时就不必写类名。

需要注意的是默认包无法用静态导入,另外如果导入的类中有重复的方法和属性则需要写出类名,否则编译时无法通过。

增强的for循环

for-each循环实现了对数组和集合的便利的统一,解决遍历数组和遍历集合的不统一。

import java.util.*;
import java.util.Collection;

public class Foreach
{
private Collection<String> c = null;
    private String[] belle = new String[4];
    public Foreach()
    {
      	belle[0] = "西施";
        	belle[1] = "王昭君";
        	belle[2] = "貂禅";
        	belle[3] = "杨贵妃";
        	c = Arrays.asList(belle);
    }
    public void testCollection(){
        for (String b : c){
              System.out.println("曾经的风化绝代:" + b);
        }
    }
    public void testArray(){
        for (String b : belle){
              System.out.println("曾经的青史留名:" + b);
        }
    }
    public static void main(String[] args){
        Foreach each = new Foreach();
        each.testCollection();
        each.testArray();
    }
}
 


对于集合类型和数组类型的,我们都可以通过foreach语法来访问它。上面的例子中,以前我们要依次访问数组,挺麻烦:

for (int i = 0; i < belle.length; i++){
        String b = belle[i];
        System.out.println("曾经的风化绝代:" + b);
}


现在只需下面简单的语句即可:

for (String b : belle){
       System.out.println("曾经的青史留名:" + b);
}

对集合的访问效果更明显。以前我们访问集合的代码:
for (Iterator it = c.iterator(); it.hasNext();){
        String name = (String) it.next();
        System.out.println("曾经的风化绝代:" + name);
}

现在我们只需下面的语句:
for (String b : c){
        System.out.println("曾经的风化绝代:" + b);
}
 
Foreach也不是万能的,它也有以下的缺点:

在以前的代码中,我们可以通过Iterator执行remove操作。

for (Iterator it = c.iterator(); it.hasNext();){
       it.remove();
}

但是,在现在的for-each版中,我们无法删除集合包含的对象。你也不能替换对象。

同时,你也不能并行的for-each多个集合。所以,在我们编写代码时,还得看情况而使用它。



可变长的参数
在java5.0中,可以使用一种变长参数,也就是例如m(String… s)的东西,编译器会自动的将方法调用时的参数适当的封装成数组
5.0之前
public class Test{
public static void main(String[] args){
}
}
JVM收到数据封装在数组里,然后传入方法
5.0之后
public class Test{
public static void main(String... s){
	m();//此时实际调用的是那个无参的m()方法
//注意:调用可变长参数的方法,只在必要时调用
		m(1,“abc”,”bcd”);
}
public static void m(){
	System.out.println(“m()”);
}
public static void m(int a,String… s){
for(String s2:s){
			System.out.println(s2+a);
}
} 
}


注意:只在必要的时候进行。同时有参数为数组,就不能使用变长参数,有变长参数,就不能使用数组,不能共存。一个方法最多只能有一个变长参数,而且是最后一个参数。


格式化输出

格式化I/O(Formatted I/O)

java.util.Sacner类可以进行格式化的输入,可以使用控制台输入,结合了BufferedReader和StringTokenizer的功能。

增加了类似C的格式化输入输出,简单的例子:

public class TestFormat{
  public static void main(String[] args){
    	int a = 150000, b = 10;
    	float c = 5.0101f, d = 3.14f;
    	System.out.printf("%4d %4d%n", a, b);
    	System.out.printf("%x %x%n", a, b);
    	System.out.printf("%3.2f %1.1f%n", c, d);
    	System.out.printf("%1.3e %1.3e%n", c, d*100);
  	}

}

输出结果为:

150000   10

249f0 a

5.01 3.1

5.010e+00 3.140e+02


类型安全的枚举

枚举也是一个类型,枚举中的对象只能定义一次并在定义时给其初始化,定义之后不能再改变其值,只能从枚举中选择其一。

enum 枚举名{
枚举值1(..),枚举值2(..),.....;
}

在5.0之前使用模式做出枚举
final class Season{
public static final Season SPRING=new Season();
public static final Season WINTER=new Season();
public static final Season SUMMER=new Season();
public static final Season AUTUMN=new Season();
private Season(){}
}
完全等价于
enum Season2{
SPRING(..),//枚举值
SUMMER(..),
AUTUMN(..),
WINTER(..);
......
}

枚举是一个反射关联的典型,反射关联,即在类的定义中有自身类型的属性。
枚举本质上也是一个类,Enum是枚举的父类。
枚举中的values()方法会返回枚举中的所有枚举值
枚举中可以定义方法和属性,最后的一个枚举值要以分号和类定义分开,枚举中可以定义的构造方法。
枚举可以实现接口,枚举不能有子类也就是final的,枚举的构造方法是private(私有的),枚举中可以定义抽象方法,可以在枚举值的值中实现抽象方法,枚举值就是枚举的对象,枚举默认是final,枚举值可以隐含的匿名内部类来实现枚举中定义抽象方法。

枚举类(Enumeration Classes)和类一样,具有类所有特性。Season2的父类是java.lang.Enum;

隐含方法Season2[] ss=Season2.values();  每个枚举类型都有的方法。enum可以在switch,case语法中使用(不加类名)。
例:
switch( s ){
case SPRING:
…………….
case SUMMER:
…………….
…………..
}

枚举类可以写有参构造方法,注意这个构造方法的权限修饰符要是private即私有的,且枚举类的构造方法默认权限修饰符不是default而是private
enum Season2{
	SPRING(“春”),
	SUMMER(“夏”),
	AUTUMN(“秋”),
	WINTER(“冬”);//注意这个分号,它代表枚举值结束
	private String name;
	Season2(String name){
		this.name=name;
}
String getName(){
	return name;
}

}
Season2.SPRING.getName();


枚举的高级用法:

枚举类中可以定义抽象方法,虽然枚举类是不能有子类的但是,枚举值可以覆盖枚举类中的定义的抽象方法。
例如下:
enum Operation{
	ADD{//可以在枚举之中覆盖抽象方法
		public double calculate(double s1,double s2){
			return s1+s2;
		}
	},
	SUBSTRACT{
		public double calculate(double s1,double s2){
			return s1-s2;
		}
	},
	MULTIPLY{
		public double calculate(double s1,double s2){
			return s1*s2;
		}
	},
	DIVIDE{
		public double calculate(double s1,double s2){
			return s1/s2;
		}
	};
	public abstract double calculate(double s1 ,double s2);//抽象方法
}

有抽象方法枚举元素必须实现该方法。

java5.0中的泛型

说明

增强了java的类型安全,可以在编译期间对容器内的对象进行类型检查,在运行期不必进行类型的转换。而在java se5.0之前必须在运行期动态进行容器内对象的检查及转换,泛型是编译时概念,运行时没有泛型

减少含糊的容器,可以定义什么类型的数据放入容器


  List<Integer> aList = new ArrayList<Integer>();

    aList.add(new Integer(1));

    // ...

    Integer myInteger = aList.get(0);
支持泛型的集合,只能存放制定的类型,或者是指定类型的子类型。

我们可以看到,在这个简单的例子中,我们在定义aList的时候指明了它是一个只接受Integer类型的ArrayList,当我们调用aList.get(0)时,我们已经不再需要先显式的将结果转换成Integer,然后再赋值给myInteger了。而这一步在早先的Java版本中是必须的。也许你在想,在使用Collection时节约一些类型转换就是Java泛型的全部吗?远不止。单就这个例子而言,泛型至少还有一个更大的好处,那就是使用了泛型的容器类变得更加健壮:早先,Collection接口的get()和Iterator接口的next()方法都只能返回Object类型的结果,我们可以把这个结果强制转换成任何Object的子类,而不会有任何编译期的错误,但这显然很可能带来严重的运行期错误,因为在代码中确定从某个Collection中取出的是什么类型的对象完全是调用者自己说了算,而调用者也许并不清楚放进Collection的对象具体是什么类的;就算知道放进去的对象“应该”是什么类,也不能保证放到Collection的对象就一定是那个类的实例。现在有了泛型,只要我们定义的时候指明该Collection接受哪种类型的对象,编译器可以帮我们避免类似的问题溜到产品中。我们在实际工作中其实已经看到了太多的ClassCastException。

用法

声明及实例化泛型类:

HashMap<String,Float> hm = new HashMap<String,Float>();
编译类型的泛型和运行时类型的泛型一定要一致。没有多态。
不能使用原始类型

GenList<int> nList = new GenList<int>(); //编译错误

Java SE 5.0目前不支持原始类型作为类型参数(type parameter)

定义泛型接口:

public interface GenInterface<T> {
  void func(T t);
}

定义泛型类:

public class ArrayList<ItemType> { ... }

public class GenMap<T, V> { ... }

例1:

public class MyList<Element> extends LinkedList<Element>
{
    public void swap(int i, int j){
        Element temp = this.get(i);
        this.set(i, this.get(j));
        this.set(j, temp);
    }

    public static void main(String[] args){
        MyList<String> list = new MyList<String>();
        list.add("hi");
        list.add("andy");
        System.out.println(list.get(0) + " " + list.get(1));
        list.swap(0,1);
        System.out.println(list.get(0) + " " + list.get(1));
    }

}


泛型的通配符"?"

? 是可以用任意类型替代。
<?>泛型通配符表示任意类型
<? extends 类型>表示这个类型是某个类型的子类型,或是某个接口的实现类
<? super 类型>表示这个类型是某个类型的父类型。
例:泛型通配符、带范围的泛型通配符
import java.util.*;
import static java.lang.System.*;
public class TestTemplate {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		List<String> l1=new ArrayList<String>();
		l1.add("abc");
		l1.add("def");
		List<Number> l2=new ArrayList<Number>();
		l2.add(1.3);
		l2.add(11);
		List<Integer> l3=new ArrayList<Integer>();
		l3.add(123);
		l3.add(456);
		
	//	print(l1);
		print(l2);
		print(l3);
	}

	static void print(List<?> l//泛型通配符){
//所有Comparable接口的实现类可以作为泛型参数
		for(Object o:l){
			out.println(o);
		}
	}

	static void print(List<? extends Number> l//带范围的泛型通配符){
//所有Number的子类可以作为泛型参数
		for(Object o:l){
			out.println(o);
		}
	}
	static void print(List<? extends Comparable> l){
//所有Comparable接口的实现类可以作为泛型参数
		for(Object o:l){
			out.println(o);
		}
	}

static void print(List<? super Number> l){
//所有Number的父类可以作为泛型参数
		for(Object o:l){
			out.println(o);
		}
	}

}

"?"可以用来代替任何类型, 例如使用通配符来实现print方法。

public static void print(GenList<?> list) {})

泛型方法的定义

把数组拷贝到集合时,数组的类型一定要和集合的泛型相同。
<...>定义泛型,其中的"..."一般用大写字母来代替,也就是泛型的命名,其实,在运行时会根据实际类型替换掉那个泛型。

需要泛型参数或返回值同时又是某个类的子类又是某个接口的实现类的时候,可以使用
<? extends Xxxx & Xxxx>这种写法,注意:接口类型要放在类的后面,且只能使用’&’符。

例:

public class Test{
<E> void copyArrayToList(E[] os,List<E> lst){
		for(E o:os){
			lst.add(o);
			}
	}

static <E extends Number> void copyArrayToList(E[] os,List<E> lst){
			for(E o:os){
			lst.add(o);
			}
		}

static<E extends Number & Comparable> void copyArrayToList(E[] os,List<E> lst){
		for(E o:os){
			lst.add(o);
		}
	}
}

受限泛型是指类型参数的取值范围是受到限制的。
extends关键字不仅仅可以用来声明类的继承关系, 也可以用来声明类型参数(type parameter)的受限关系。例如, 我们只需要一个存放数字的列表, 包括整数(Long, Integer, Short), 实数(Double, Float), 不能用来存放其他类型, 例如字符串(String), 也就是说, 要把类型参数T的取值泛型限制在Number极其子类中.在这种情况下, 我们就可以使用extends关键字把类型参数(type parameter)限制为数字
只能使用extends不能使用 super,只能向下,不能向上。
注意:只有参数表中可以使用<?> ,定义泛型时用 <E>

泛型类的定义

我们也可以在定义类型中使用泛型
注意:静态方法中不能使用类的泛型,因为泛型类是在创建对象的时候给定泛型。
例:
class MyClass<E>{
	public void show(E a){
		System.out.println(a);
	}
	public E get(){
		return null;
	}
	
}


受限泛型

class MyClass <E extends Number>{
	public void show(E a){

	}
}


泛型与异常

泛型参数在catch块中不允许出现,但是能用在方法的throws之后。例:

import java.io.*;

interface Executor<E extends Exception> {
    void execute() throws E;
}

public class GenericExceptionTest {
    public static void main(String args[]) {
        try {
              Executor<IOException> e = new Executor<IOException>() {
                  public void execute() throws IOException{
                      // code here that may throw an
                      // IOException or a subtype of
                      // IOException
                  }
                 };
              e.execute();
        } catch(IOException ioe) {
              System.out.println("IOException: " + ioe);
              ioe.printStackTrace();
        }
    }
}



泛型的一些局限型

catch不能使用泛型,在泛型集合中,不能用泛型创建对象,不允许使用泛型的对象。

不能实例化泛型

T t = new T(); //error

不能实例化泛型类型的数组

T[] ts= new T[10];   //编译错误

不能实例化泛型参数数

Pair<String>[] table = new Pair<String>(10); // ERROR

类的静态变量不能声明为类型参数类型

public class GenClass<T> {
  private static T t;   //编译错误
}
静态方法可以是泛型方法,但是不可以使用类的泛型。

泛型类不能继承自Throwable以及其子类

public GenExpection<T> extends Exception{}   //编译错误

不能用于基础类型int等

Pair<double> //error

Pair<Double> //right