java编程笔记19 java高级特性

1,自动装箱与拆箱

自动装箱是指把基本数据类型封装成类对象,拆箱是指把类对象拆成基本数据类型。

例如下列代码在java 5.0以后都是可以编译通过的

//自动装箱
Integer in = 3;
Short sh = 2;
Long lo = 3L;
		
Double dbl = 3.4D;
Float fl = 1.2F;
		
Byte bt = 12;
Character cht = 'c';
		
// 自动拆箱
int i = new Integer(3);
short s = new Short((short)1);
long l = new Long(3L);
		
double d = new Double(2.3D);
float f = new Float(1.2F);
		
byte b = new Byte((byte)23);
char ch = new Character('a');

而在java5.0以前则不行,因为两边的数据类型不一样,一个是基本数据类型一个是对象,必须通过调用wrapper类的方法来实现对象和基本数据类型之间的转化

关于包装类在这里不详述。

2,新的for/in循环,

只需要在for循环里指出遍历的元素类型,和遍历的对象即可:

package com.book.ch10.java5;

import java.util.ArrayList;
import java.util.List;

public class JForInArray {

	public static void main(String[] args) {

		String[] array = { "a", "b", "c", "d" };

		for (String s : array) {
			System.out.println("遍历数组:" + s);
		}

		List<String> list = new ArrayList<String>();

		list.add("A");
		list.add("b");
		list.add("C");
		list.add("D");
		
		for (String obj : list) {
			System.out.println("遍历集合:" + obj);
		}

	}

}

3,可变长参数法

定义一个可变长参数的方法是在参数类型的后面加上省略号,然后加上可变长参数名。可变长参数在方法内部表现为数组,可以使用传统的数组遍历方式来使用数组,也可以使用新的for/in循环:

package com.book.ch10.java5;

public class JVarargsTest {

	public static double avg(double... values) {//可变长参数的定义方法

		double total = 0;
		int count = values.length;

		for (double i : values) {//可变长参数的使用
			total += i;
		}

		return total / count;
	}

	public static void main(String[] args) {
		System.out.printf("平均数为 %s. %n", avg(3, 4.2, 2));
		System.out.printf("平均数为 %s. %n", avg());
		System.out.printf("平均数为 %s. %n", avg(new double[] { 3, 4.2, 2 }));
	}

}

4,协变式返回类型

允许在覆盖父类方法的时候,使父类方法的返回值更加具体。例如ArrayList类的get(int index)返回的是Object,继承ArrayList之后可以覆盖get方法并修改返回值为String,因为String也是Object的子类。在java5.0版本以前,这是不允许的。

package com.book.ch10.java5;

import java.util.ArrayList;
import java.util.List;

@SuppressWarnings(value="serial")
public class JCovariantReturnTypesTest extends ArrayList {

	@Override
	//可以这样来覆盖父类中的方法,在5.0以前是不允许在覆盖的时候返回值类型跟父类不一样的
	public String get(int index) {
		return (String)super.get(index);
	}

	public static void main(String...args){
		JCovariantReturnTypesTest list = new JCovariantReturnTypesTest();
		
		list.add("字符串");
		
		// 可以直接返回 String 类型 而不是父类中的 Object
		String result = list.get(0);
		System.out.printf("%s", result);
	}
	

}

5,静态导入

即impot Static指令导入某个类的静态方法和静态变量,在使用的时候就可以直接使用变量名和方法名,而不用再带上“类名. ”了。

package com.book.ch10.java5;

// 静态导入变量
import static java.lang.Math.PI;
// 静态导入方法
import static java.lang.Math.sin;
// 静态导入所有的方法跟变量
import static java.lang.Math.*;

public class JStaticImportTest {
	
	public static void main(String[] args){
		// 直接使用方法和变量,无需 Math 前缀
		System.out.printf("sin(%s) = %s%n", PI, sin(PI));
		System.out.printf("cos(%s) = %s%n", PI, cos(PI));
	}
	
}

6,泛型

在这里只介绍最基本的语法,后面将详细介绍

类与方法都可以被泛型化,泛型避免了一些运行时错误,使得许多错误在编译阶段就能发现。

类泛型ArrayList<E>代表的意思是ArrayList存放的数据类型是E类型,E代表一个类的类型

方法泛型public E get(int index)代表方法的返回值是E型的

看一个例子:

package com.book.ch10.java5;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class JGenericTest {
	
	public static void main(String[] args){
		
		// 范型 限制为 Date 类型
		List<Date> list = new ArrayList<Date>();
		
		list.add(new Date());
		list.add(new Date());
		list.add(new Date());
		
		// 无需 ClassCast. 
		Date date = list.get(0);
		System.out.printf("%s %n", date);
		
		for(Date dd : list){
			System.out.printf("for/in 循环:%1$tF %1$tT%n", dd);
		}
		
		
	}

}

注意,泛型编程只能使用类,不能使用基本类型。

集合中使用多个泛型的一个例子:

package com.book.ch10.java5;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JHashMapGeneric {

	public static void main(String[] args) {
		
		Map<String, Date> map = new HashMap<String, Date>();//多个泛型
		
		map.put("time_1", new Date());
		map.put("time_2", new Date());
		map.put("time_3", new Date());
		
		for(String key : map.keySet()){
			Date date = map.get(key);
			System.out.printf("Key: %1$s, Value: %2$tF %2$tT%n", key, date);
		}
		
	}

}

再来看一下泛型通配符:通配符只能用来进行类型安全检查,而不能用来声明具体的类泛型

<?>代表任何类型,不过单独使用?基本没有什么用(单独一个?也就是不用泛型的意思),一般与extends和super一起用

<?>与extends一起表示指定类型及其所有子类

<?>与super一起表示指定类型及其所有父类

由于通配符只能进行类型安全检查,不能用来声明具体的泛型类,故下面的用法是错误的

List <?> = new ArrayList<?>   //不能用来做声明用

看下面用通配符做类型检查的一个例子:

package com.book.ch10.java5;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class JWildCard {
	
	//通配符指定接受的list可以是Number及其子类
	public static void numberList(List<? extends Number> list){
		for(Number num : list){
			System.out.printf("输出数字:%1$s %n", num);
		}
	}
	
	//同上
	public static void dateList(List<? extends Date> list){
		for(Date date : list){
			System.out.printf("输出日期:%1$tF %1$tT%n", date);
		}
	}
	
	public static void main(String[] args){
		
		List<Date> dateList = new ArrayList<Date>();//类型声明要用具体的泛型
		List<Integer> intList = new ArrayList<Integer>();
		
		dateList.add(new Date());
		dateList.add(new Date());

		intList.add(3);
		intList.add(6);
		
		numberList(intList);
		dateList(dateList);
	}

}

泛型化一个类是在类名后面定义泛型类型,泛型化一个方法需要在方法名的返回类型前定义泛型类型:下面写一个自己的泛型:

package com.book.ch10.java5;

import java.util.Date;

public class JGenericMethod {

	// 范型化类. 在类名后使用<>定义了范型类型 T.
	static class A<T> {
		// 定义之后直接使用 T 即可
		public T generic(T t){
			return t;
		}
	}
	
	static class B {
		// 范型化方法. 在方法返回类型前使用<>定义范型类型 T
		public <T> T generic(T t){
			return t;
		}
		// 范型化方法. 在方法返回类型前使用<>定义范型类型 T, 该范型类型只能为 Date 及其子类
		public <T extends Date> T genericDate(T t){
			return t;
		}
	}
	
	public static void main(String[] args){
		
		A<String> a = new A<String>();
		String ss = a.generic("一个字符串");
		
		B b = new B();
		String ss2 = b.generic("另一个字符串");
		Date date = b.genericDate(new Date());
		
	}
	
}

7,枚举类型

枚举类型不能在方法内部声明,只能声明为一个类变量,

public enum Sex{MALE,FEMAL,UNKNOW};

枚举类型里德变量是实实在在的对象,可以把他们看成是static,final,public的

package com.book.ch10.java5;

public class JEnumeration {
	
	public static enum Sex { MALE, FEMALE, UNKOWN, };
	
	public static void main(String[] args){
		
		System.out.printf("Sex.FEMALE.toString(): \t%s %n", Sex.FEMALE.toString());
		System.out.printf("Sex.FEMALE.ordinal(): \t%s %n", Sex.FEMALE.ordinal());
		System.out.printf("Sex.FEMALE.getClass(): \t%s %n", Sex.FEMALE.getClass());
		
		System.out.printf("%n遍历所有的 Sex 枚举变量: ");
		
		for(Sex sex : Sex.values()){
			System.out.printf("%s, ", sex);
		}
		
		switch(Sex.FEMALE){
		case MALE:
			// do something
			break;
		case FEMALE:
			// do something
			break;
		case UNKOWN:
			// do something
			break;
		default:
			// do something
		}
		
	}

}

下面来看一下扩展枚举类型,enum和class,interface一样是一种对象。因此它可以扩展,添加属性或方法,跟interface不能有构造函数一样,enum也有一些限制:

enum内部可以有构造方法,但不能有public的构造方法

enum内置对象间必须用逗号隔开,声明完所有的内置对象后用分号结束

enum内置对象必须使用声明的构造函数,否则编译错误

看一个例子:

package com.book.ch10.java5;

public class JEnumTest {
	
	static enum Type {
		// 内置的枚举类型对象
		// 各枚举类型对象之间用逗号隔开。
		MANAGER("经理", 10000), 
		ASSISTANT("助理", 6000), 
		WORKER("员工", 4000),
		;//分号结束
		
		// 扩展的属性
		private String name;
		private double pay;
		
		// 构造函数 不能为 public 
		Type(String name, double pay){
			this.name = name;
			this.pay = pay;
		}
	}
	
	
	static class Person {
		
		public Person(String name, Type type){//	注意person的类型	
this.name = name; this.type = type; } private String name; private Type type; public String getName() { return name; } public void setName(String name) { this.name = name; } public Type getType() { return type; } public void setType(Type type) { this.type = type; } } public static void printInfo(Person person){ System.out.printf("姓名:%1$s, \t职业:%2$s, \t岗位薪水:%3$s %n", person.getName(), person.getType().name, person.getType().pay); } public static void main(String[] args){ Person p1 = new Person("张三", Type.MANAGER); Person p2 = new Person("李四", Type.WORKER); Person p3 = new Person("王五", Type.ASSISTANT); printInfo(p1); printInfo(p2); printInfo(p3); } }


你可能感兴趣的:(java编程)