JDK 1.5 新特性
一、 不定长参数
使用原始的参数 无法做到不定长
3. 不定长参数
大家可以试一下传入不同的参数会调用下边的那个方法,猜测下调用过程中对徐方法进行选择的优先级
二、自动拆箱装箱
1. 基本数据类型和对应的包装类可以直接交互性操作
a) 自动装箱 基本数据类型可自动转换成对应的包装类
b) 自动拆箱 包装数据类型可直接转换成对应的基本数据类型
三、静态导入
1. 将一个类的静态成员 使用导包的形式导入到一个类中
拥有静态数据的类
不使用静态导入的使类的静态数据1 、
使用静态导入时使用类的静态数据2 、
四、增强的for 循环
语法
for(容器中的数据类型 变量名称 : 容器){
//循环体
}
使用for 循环
使用迭代器:
使用增强的for 循环
1.不会出现下表越界
增强的for 循环中有时报 NullPointerException:
五、泛型
1. 如何在集合中保证数据的类型安全?
如何保证数据的类型安全?
例如 我想在一个集合中只能存放String
测试函数:
2. 什么是泛型? 怎么用泛型?
泛型就是一种通用的类型,例如List<E>中的<E>就是一种泛型的应用,E是一种类型参数,可以把E看作是一个占位符,就像方法的形式参数是运行时传递值的占位符一样。等待参数传入后决定E是什么样的数据类型。
有了泛型之后
自定义泛型
1.泛型可以出现在什么地方?
1. 定义一个属性
2. 作为方法的形式参数
3. 作为方法的返回值
2.泛型的确定方法
1.在创建类对象的时候确定
2.在子类继承的时候确定
父类:
子类1:直接指定
测试1 :
测试:
3. 泛型和数组 、 泛型可以继承吗?数组间具有
泛型是不可以继承的,原因在于泛型泛型的目的是保证数据的类型安全。如果泛型性具有继承的特性则会破坏泛型类型安全的承诺。
举例如下:
数组间:
以上的两个例子说明了泛型不具有继承的特性,那么他是如何保证数据的类型安全的呢?
下面一个例子我们看一下数组的协变性导致的结果?
数组协变性的坏处:
编译通过,运行异常
但是在泛型中不具有协变性,就会有效的避免这一个问题
4. 泛型通配符 <?>
a) 遍历一个集合。
b) 不改变里面的数据
c) 不能确定要传入的参数的具体的数据类型
java可以使用泛型,在定义类型形参时设定类型的上限,用于表示传给该类型形参的实际类型必须是该上限类型,或该上限类型的子类。
下面程序 解释了这种用法<方法上>
for (Number num : list) {System.out.println(num);}}} 类上5. 泛型方法表示声明的泛型只在本方法中有效如果我们想把一个数组添加到一个集合中
如果还有一个String的数组需要添加进一个集合中呢?
语法
泛型的下限
将一个集合的数据拷贝到另一个集合
6. java中的泛型不是真正的泛型 , 在编译期间有效运行期间无效。
因为java中的泛型不是真正意义上的泛型,java的泛型在编译期间会被擦除,JVM不知道要构造的类是什么,因此也就不知道使用什么样的构造函数
如List<String> 和 List<Integer> 在运行期间都会被JVM认为是List类型,及JVM是不承认泛型的,所以无法创建泛型的对象。
六、注解
上面这段代码中d.getDate(); 会被打上一段横线表示该段代码不在建议被使用,我们可以再Date类源码中看到该方法上有这样一个注解@Deprecated
在编辑器中我们可以很容易的通过这个注解明白这个方法是已经不被建议使用的。
Thread 类的 suspend() 方法
父类:
子类:
自定义注解
测试:
七、枚举
主要是用于限制数据范围
枚举类的所有实例,必须在枚举类的第一行显式的列出,否则这个类永远不能产生实例。列出这些实例时,系统会自动添加 public static final 修饰
/*
* 一旦为枚举显示定义了带参数的构造器,
* 列出枚举值时就必须对应的传入参数
*/
一、 不定长参数
使用原始的参数 无法做到不定长
1. 使用原始参数,无法做到不定长
public class Test {
public static void main(String[] args) {
test(1);
test(2,23);
}
private static void test(int i, int j) {
}
private static void test(int a) {
}
}
2. 使用数组,可以做到不定长参数,有一个问题:无法不传参数
public class Test {
public static void main(String[] args) {
int[] ins = new int[]{1,2,3};
test(ins);
test();
}
private static void test(int[] ins) {
for (int i = 0; i < ins.length; i++) {
int j = ins[i];
System.out.println(j);
}
}
}
3. 不定长参数
语法 ( 类型... 形参 )
public class Test {
public static void main(String[] args) {
int[] arr = new int[]{1,2,3};
test(arr);
test(1,2,3);
test();
}
private static void test(int...args) {
for (int i = 0; i < args.length; i++) {
int j = args[i];
System.out.println(j);
}
}
}
4. 不能和数组进行重载,不定长参数的底层本身也是借助于数组实现的,因此不定长参数是不能与数组进行重载的
public class Test {
// 下面的两个方法的重载是不能通过编译
private static void test(int...ins) {
for (int i = 0; i < ins.length; i++) {
int j = ins[i];
System.out.println(j);
}
}
private static void test(int[] ins) {
for (int i = 0; i < ins.length; i++) {
int j = ins[i];
System.out.println(j);
}
}
}
大家可以试一下传入不同的参数会调用下边的那个方法,猜测下调用过程中对徐方法进行选择的优先级
public class Test {
public static void main(String[] args) {
test(null) ;
}
private static void test(int...ins) {
System.out.println("int...");
}
private static void test(Integer...ins) {
System.out.println("Integer...");
}
private static void test(Object ins) {
System.out.println("Object");
}
private static void test(int ins) {
System.out.println("int");
}
private static void test(Integer ins) {
System.out.println("Integer");
}
private static void test() {
System.out.println("-----------");
}
}
5. 关于不定长参数,需要特别注意的一点事,不定长参数必须在最后一位
public class Test {
// 此方法的编译是不被
private static void test(int...args ,String name ) {
for (int i = 0; i < args.length; i++) {
int j = args[i];
System.out.println(j);
}
}
}
二、自动拆箱装箱
1. 基本数据类型和对应的包装类可以直接交互性操作
a) 自动装箱 基本数据类型可自动转换成对应的包装类
b) 自动拆箱 包装数据类型可直接转换成对应的基本数据类型
public class Test {
public static void main(String[] args) {
test(123);
int a = test1();
//自动拆箱
System.out.println(a);
}
private static int test1() {
return 212;
}
private static void test(int i) {
//自动装箱
Integer x = i ;
System.out.println(x);
}
}
三、静态导入
1. 将一个类的静态成员 使用导包的形式导入到一个类中
拥有静态数据的类
public class StaticData {
public static int CN = 0 ;
public static int JP = 0 ;
public static int EN = 0 ;
}
不使用静态导入的使类的静态数据1 、
public class Test {
public static void main(String[] args) {
test();
}
private static void test() {
int language = StaticData.CN;
}
}
使用静态导入时使用类的静态数据2 、
public class Test {
public static void main(String[] args) {
System.out.println("这个月的第"+DAY_OF_MONTH+"天");
System.out.println("这个周的第"+DAY_OF_WEEK+"天");
}
}
四、增强的for 循环
语法
for(容器中的数据类型 变量名称 : 容器){
//循环体
}
使用for 循环
public static void main(String[] args) {
List list = new ArrayList();
list.add("stirng1");
list.add("string2");
list.add("string3");
list.add("a");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
使用迭代器:
public static void main(String[] args) {
Set set = new HashSet ();
set.add("stirng1");
set.add("string2");
set.add("string3");
set.add("a");
Iterator iter = set.iterator();
for (; iter.hasNext(); ) {
System.out.println(iter.next());
}
}
public static void main(String[] args) {
Set set = new HashSet ();
set.add("stirng1");
set.add("string2");
set.add("string3");
set.add("a");
Iterator<String> iter = set.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
}
使用增强的for 循环
public static void main(String[] args) {
Set set = new HashSet ();
set.add("stirng1");
set.add("string2");
set.add("string3");
set.add("a");
for (String s : set) {
System.out.println(s);
}
}
1.不会出现下表越界
2.不用进行非空验证
public static void main(String[] args) {
List list = new ArrayList ();
list.add("stirng1");
list.add("string2");
list.add("string3");
list.add("a");
for (int i = 0; i < list.size(); i++) {
String string = list.get(i);
if ("a".equals(string))
list.remove(i);
}
for (int i = 0; i < list.size(); i++) {
String string = list.get(i);
System.out.println(string);
}
}
public static void main(String[] args) {
List list = new ArrayList ();
list.add("stirng1");
list.add("string2");
list.add("string3");
list.add("a");
Iterator iter = list.iterator();
while(iter.hasNext()){
String o = iter.next();
if("a".equals(o))
list.remove(o);
}
}
增强的for 循环中有时报 NullPointerException:
其原因是集合未被初始化,即没有个集合分配内空间,增强的for循环的原理是根据集合中的方法,找到集合中实际填充的元素的数量,然后依次进行迭代。因此,如果集合未被初始化的时候就不能调用其中的方法产生NullPointerException
public class Test{
public static void main(String[] args){
ArrayList<Integer> list = null ;
For( Integer integer : list){
System.out.println(integer);
}
}
}
五、泛型
1. 如何在集合中保证数据的类型安全?
如何保证数据的类型安全?
例如 我想在一个集合中只能存放String
public class StringList {
private List list = new ArrayList();
public boolean add(String string){
return list.add(string);
}
public String get(int index){
return (String) list.get(index);
}
public int size(){
return list.size();
}
}
测试函数:
public static void main(String[] args) {
StringList list = new StringList();
list.add("string");
list.add(123); // this is wrong
}
2. 什么是泛型? 怎么用泛型?
泛型就是一种通用的类型,例如List<E>中的<E>就是一种泛型的应用,E是一种类型参数,可以把E看作是一个占位符,就像方法的形式参数是运行时传递值的占位符一样。等待参数传入后决定E是什么样的数据类型。
有了泛型之后
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("string");
list.add(123); // this is wrong
}
自定义泛型
1.泛型可以出现在什么地方?
1. 定义一个属性
2. 作为方法的形式参数
3. 作为方法的返回值
public class Generic<E> {
private E e;
public void fun(E e) {
}
public E fun1() {
return e;
}
}
2.泛型的确定方法
1.在创建类对象的时候确定
public static void main(String[] args) {
Generic<String> gen = new Generic<String>();
gen.fun("string"); //参数类型为String
}
2.在子类继承的时候确定
父类:
public class Father<T> {
public void fun(T String){
}
}
子类1:直接指定
public class Child extends Father<String> {
}
测试1 :
public static void main(String[] args) {
Child child = new Child();
child.fun("string"); // only string is right
}
3.泛型的传递性
子类2:public class Child2<T> extends Father<T> {
public void test(T t){
}
}
测试:
public static void main(String[] args) {
Child2<String> child = new Child2<String>();
child.test("string"); // only string is allowed
child.fun ("string"); // only stirng is allowed
}
3. 泛型和数组 、 泛型可以继承吗?数组间具有
泛型是不可以继承的,原因在于泛型泛型的目的是保证数据的类型安全。如果泛型性具有继承的特性则会破坏泛型类型安全的承诺。
举例如下:
数组间:
public class Child2<T> extends Father<T> {
public static void main(String[] args) {
Integer[] dubs = new Integer[]{1,2,3,4,5};
test1(dubs);
}
public static void test1(Number[] number) {
for (int i = 0; i < number.length; i++) {
System.out.println(number[i]);
}
}
}
泛型间:
public class Child2<T> extends Father<T> {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(12);
list.add(2);
list.add(5);
test1(list) ;
}
public static void test1(List<Number> number) {
for (Number num : number) {
System.out.println(number);
}
}
}
以上的两个例子说明了泛型不具有继承的特性,那么他是如何保证数据的类型安全的呢?
下面一个例子我们看一下数组的协变性导致的结果?
数组协变性的坏处:
编译通过,运行异常
public class Test {
public static void main(String[] args) {
Integer[] ins = new Integer[10];
Number[] nums = ins;
nums[0] = 12.23 ;
}
}
但是在泛型中不具有协变性,就会有效的避免这一个问题
4. 泛型通配符 <?>
a) 遍历一个集合。
b) 不改变里面的数据
c) 不能确定要传入的参数的具体的数据类型
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("string");
list.add("string1");
list.add("string2");
test1(list);
}
public static void test1(List<?> list) {
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
java可以使用泛型,在定义类型形参时设定类型的上限,用于表示传给该类型形参的实际类型必须是该上限类型,或该上限类型的子类。
下面程序 解释了这种用法<方法上>
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
test(list);
List<Double> list2 = new ArrayList<Double>();
list2.add(1.1);
list2.add(2.2);
list2.add(3.3);
test(list2);
// List<String> list3 = new ArrayList<String>();
// list3.add("a");
// list3.add("b");
// list3.add("c");
// test(list3) ;
}
public static void test(List<? extends Number> list){<pre name="code" class="java">public class GenericLimit<E extends Number> {
public void fun(E num) {
}
public static void main(String[] args) {
GenericLimit<Integer> nums = new GenericLimit<Integer>();
nums.fun(123);
// nums.fun("" );
}
}
for (Number num : list) {System.out.println(num);}}} 类上5. 泛型方法表示声明的泛型只在本方法中有效如果我们想把一个数组添加到一个集合中
static void fun(Object[] objs , List<Object> list){
for (int i = 0; i < objs.length; i++) {
list.add(objs[i]);
}
}
如果还有一个String的数组需要添加进一个集合中呢?
static void fun(String[] objs , List<Object> list){
for (int i = 0; i < objs.length; i++) {
list.add(objs[i]);
}
}
语法
修饰符 <T> 返回值 方法名(参数列表){ // 方法体 }
public class GenericMethod {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
String[] string = new String[] { "a", "b", "c" };
fun(string, list);
List<Integer> list2 = new ArrayList<Integer>();
Integer[] ins = new Integer[] { 1, 2, 3 };
fun(ins, list2);
// fun(string , list2);
}
static <T> void fun(T[] objs, List<T> list) {
for (int i = 0; i < objs.length; i++) {
list.add(objs[i]);
}
}
}
泛型的下限
将一个集合的数据拷贝到另一个集合
public class Test {
public static void main(String[] args) {
List<Child> src = new ArrayList<Child>();
Child child = new Child();
child.name = "zhangsan";
Child child1 = new Child();
child1.name = "lisi";
src.add(child);
src.add(child1);
List<Father> dest = new ArrayList<Father>();
test(dest, src);
}
/**
* 将一个集合的数据拷贝到另一个集合
*
* @param <T>
*/
public static <T> void test(List<? super T> dest, List<T> src ) {
for (T t : src) {
dest.add(t);
}
}
}
6. java中的泛型不是真正的泛型 , 在编译期间有效运行期间无效。
因为java中的泛型不是真正意义上的泛型,java的泛型在编译期间会被擦除,JVM不知道要构造的类是什么,因此也就不知道使用什么样的构造函数
如List<String> 和 List<Integer> 在运行期间都会被JVM认为是List类型,及JVM是不承认泛型的,所以无法创建泛型的对象。
六、注解
语法
public @interface name{
//属性
public String name();
}
public static void main(String[] args) {
Date d = new Date();
int in = d.getDate ();
System.out.println("这个月的第 "+in+" 天");
Calendar c = Calendar.getInstance();
int x = c.get(Calendar.DAY_OF_MONTH);
System.out.println("这个月的第 "+x+" 天");
}
上面这段代码中d.getDate(); 会被打上一段横线表示该段代码不在建议被使用,我们可以再Date类源码中看到该方法上有这样一个注解@Deprecated
<strong>@Deprecated</strong>
public int getDate() {
return normalize().getDayOfMonth();
}
其doc文档中有这样的描述
@Deprecated
<strong>Deprecated. As of JDK version 1.1, replaced by Calendar.get(Calendar.DAY_OF_MONTH).</strong>
Returns the day of the month represented by this Date object. The value returned is between 1 and 31 representing the day of the month that contains or begins with the instant in time represented by this Date object, as interpreted in the local time zone.
Returns:
the day of the month represented by this date.
See Also:
java.util.Calendar
在编辑器中我们可以很容易的通过这个注解明白这个方法是已经不被建议使用的。
类似的还有很多,如:
Thread 类的 suspend() 方法
* Deprecated is one that programmers
* are discouraged from using, typically because it is dangerous,
* or because a better alternative exists. Compilers warn when a
* deprecated program element is used or overridden in non-deprecated code.
*
* @since 1.5
@override
父类:
public class Father {
public void fun() {
}
}
子类:
public class Child extends Father {
@Override
public void fun() {
}
}
自定义注解
@Target({ElementType.FIELD,ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME )
public @interface MyAnnotation {
public String name() ;
public int level() default 123 ;
}
测试:
public class TestAnnotation {
@MyAnnotation(name = "")
private int s = 0 ;
@MyAnnotation(name = "" , level = 10)
public void fun(){
}
}
七、枚举
主要是用于限制数据范围
public enum MYEnum {
SPRING , SUMMER , FALL ,WINTER
}
public class Test {
public static void main(String[] args) {
fun(MYEnum.SPRING);
}
public static void fun(MYEnum e){
System.out.println(e);
}
}
枚举类的所有实例,必须在枚举类的第一行显式的列出,否则这个类永远不能产生实例。列出这些实例时,系统会自动添加 public static final 修饰
/*
* 一旦为枚举显示定义了带参数的构造器,
* 列出枚举值时就必须对应的传入参数
*/
public enum G {
MALE("男"),FEMALE("女");
private String name ;
private G(String name ){
this.name = name ;
}
public String getName() {
return name;
}
}