Java基础——jdk1.5新特性及集合与数组的转换

本文深入探讨了JDK1.5引入的重要特性,包括泛型的概念、使用及注意事项,展示了如何利用泛型提高代码的安全性和灵活性。同时,文章讲解了泛型类、泛型方法、泛型接口的定义与应用,以及泛型通配符的使用场景。此外,还介绍了增强for循环和可变参数的使用技巧,以及集合与数组间的转换方法。
jdk1.5的新特性

泛型是一种泛泛的类型,泛指某一种类型,是在创建对象或者调用方法或者实现接口才明确的类型。

泛型好处提高安全性(将运行期的类型转换错误提前到编译期),省去强转的麻烦。

泛型使用注意事项

  1. <>中放的必须是引用数据类型;
  2. 前后的泛型必须一致,或者后面的泛型可以省略不写(1.7的新特性菱形泛型) (建议后面的也写全);
  3. 在创建对象或者调用方法或者实现接口明确泛型的时候,尽量不要明确成Object,因为这样做没有意义(泛型的由来就是由Object的转型的问题得到的);
  4. 泛型是JDK1.5出现的。

代码演示:

public static void demo1() {
    ArrayList list = new ArrayList();
    list.add(110);//添加一个Integer类型的 110,在没有使用泛型的时候 list可以添加任意的引用类型  
    list.add(true);	//添加一个Boolean类型的 true
    list.add(new Person("张三", 23));	//添加一个Person
    Iterator it = list.iterator();
    while(it.hasNext()) {
        System.out.println(it.next());	//将集合里面的元素打印出来
    }
}

public static void demo2() {
    ArrayList list = new ArrayList();
    list.add(110);			
    list.add(true);				
    list.add(new Person("张三", 23));	
    Iterator it = list.iterator();
    while(it.hasNext()) {
    	//如果我想使用Person的特有功能 需要强制转换成Person类型
        Person p = (Person)it.next();//编译不报错, 运行的时候立刻报错,因为存储的 110 和 true 并不是Person类型 单却强制转换成Person类型 会报出类型转换错误			
        System.out.println(p.getName() + "..." + p.getAge());
    }
}

//ArrayList存储字符串并遍历泛型版
public static void demo3() {
    ArrayList<Person> list = new ArrayList<>();		//<Person>规定 list对象里面必须存储Person类型的元素,存储其他类型的编译就会报错
    list.add(new Person("张三", 23));
    list.add(new Person("李四", 24));
    list.add(new Person("王五", 25));
    list.add(new Person("赵六", 26));

    Iterator<Person> it = list.iterator();			//获取的迭代器也是Person类型的泛型
    while(it.hasNext()) {
        Person p = it.next();				//it.next()获取到的元素 就不再是Object了,泛型里面规定的类型 it.next()就获取什么样类型的元素,所以就不用强制类型转换了
        System.out.println(p.getName() + "..." + p.getAge());
    }
}


public static void main(String[] args) {
    //ArrayList<int> list = new ArrayList<int>();		//编译报错 <>中放的必须是引用数据类型 
    //ArrayList<Object> list = new ArrayList<Person>();	//编译报错 集合的泛型要保证前后的数据类型一致
    ArrayList<Object> list = new ArrayList<>();//泛型最好不要定义成Object,没有意义,1.7版本的新特性,菱形泛型,后面的<>可以不用填写
    list.add("aaa");
    list.add(true);
}
泛型类: public class 类名<泛型类型1,泛型类型2,…>{}
public class Worker<QQ> {
    public void show(QQ qq){
    	System.out.println(qq);
    }
}
public class Worker<QQ,MM,DD,RR> {	//可以写一个泛型 也可以写多个
    public void show(QQ qq){
    	System.out.println(qq);
    }
}
泛型非静态方法: public <泛型类型> 返回类型 方法名(泛型类型 变量名){}

代码演示:

public class Demo1_Generic {
	public static void main(String[] args) {
		/*Tool t = new Tool();
		t.show("abc");		//调用show(String s)方法 传入一个"abc"
		t.show(100);*/		//调用show(Integer i)方法 传入一个100
        //如果想继续接着调用一个show(Student s)方法, 就需要继续修改Tool类,再继续编写一个show(Student s)方法 才能调用
        //如果想继续接着调用一个show(Animal a)方法, 就需要继续修改Tool类,再继续编写一个show(Animal a)方法 才能调用
        //如果想继续接着调用一个show(Worker w)方法, 就需要继续修改Tool类,再继续编写一个show(Worker w)方法 才能调用
        //这样修改  将无穷无尽,所以用下面的泛型类改进代码

        /*Tool1<String> t = new Tool1<>();	//想调用show方法 传入一个"abc" 那么就创建一个泛型为String的对象
		t.show("abc");
		
		Tool1<Integer> t1 = new Tool1<>();	//想调用show方法 传入一个100 那么就创建一个泛型为Integer的对象
		t1.show(100);

		Tool1<Student> t2 = new Tool1<>();	//想调用show方法 传入一个Student 那么就创建一个泛型为Student的对象
		t2.show(new Student());*/		
        //如果想接着调用show方法 传入一个Animal 就又要创建一个泛型为Animal的对象 ,每次都要创建一个新的对象 浪费空间 所以用下面的泛型方法改进

        Tool2 t = new Tool2();	
        t.show("abc");	//调用show方法的时候就明确了QQ是String类型
        t.show(100);//调用show方法的时候就明确了QQ是Integer类型
        t.show(new Student());//调用show方法的时候就明确了QQ是Student类型
        //想传什么样的类型都可以 而且代码非常的简单
    }
}
public class Tool {
    public void show(String s) {
        System.out.println(s);
    }
    public void show(Integer i) {
        System.out.println(i);
    }
}

public class Tool1<QQ> {
    public void show(QQ qq){
        System.out.println(qq);
    }
}
public class Tool2 {
    public <QQ>void show(QQ s){
        System.out.println(s);
    }
}
泛型静态方法: public static <泛型类型> 返回类型 方法名(泛型类型 变量名){}
public class Tools<Q> {	
    /*public static void show(Q q) {		//编译报错,因为静态的 优先于对象而存在
			System.out.println(q);
	}*/
    public static<W> void print(W w) {		//静态方法必须声明自己的泛型
        System.out.println(w);
    }
}
泛型接口:public interface 接口名<泛型类型>

子类在实现父接口的时候可以明确泛型,也可以直接沿用父类的泛型

代码演示:

interface Inter<T> {
    public void show(T t);
}

class Demo implements Inter<String> {		//子类在实现父接口的时候 可以明确泛型 明确成了String类型
    @Override
    public void show(String t) {
        System.out.println(t);
    }
}

class Demo<T> implements Inter<T> {		//也可以直接沿用父类的泛型 T
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}
泛型-通配符:

A:泛型通配符<?>任意类型

List<?> list = new ArrayList(); //当右边的泛型是不确定时,左边可以指定为?
B:<? extends E >明确泛型的时候明确成E或者E的儿子
代码演示:

public static void main(String[] args) {
    ArrayList<Person> list1 = new ArrayList<>();
    list1.add(new Person("张三", 23));
    list1.add(new Person("李四", 24));
    list1.add(new Person("王五", 25));

    ArrayList<Student> list2 = new ArrayList<>();
    list2.add(new Student("赵六", 26));
    list2.add(new Student("周七", 27));

    //boolean addAll(Collection<? extends E> c)
    list1.addAll(list2);		//Student 是Person的儿子 所以 可以添加成功
    System.out.println(list1);
}

C:<? super E >明确泛型的时候明确成 E或者E的父类

增强for循环

为了简化数组或者集合的遍历而出现的(JDK1.5出现的)

for(集合或者数组里面元素的数据类型 变量名 : 数组或者集合){
	直接使用变量名就ok;
}

代码演示:

public static void demo1() {
    int[] arr = {11,22,33,44,55};
    for (int i : arr) {		//增强for循环可以遍历数组
        //增强for循环在遍历数组或者集合的时候,优点:代码的书写确实简单了,但缺点是遍历时候没有索引,如果想用索引的时候,就请用普通for循环
        System.out.println(i);
    }

    ArrayList<String> list = new ArrayList<>();
    list.add("a");
    list.add("b");
    list.add("c");
    list.add("d");

    for (String string : list) {	//增强for循环可以遍历集合
        System.out.println(string);
    }
}

遍历过程中能否删除元素总结:
1)普通for循环在遍历的时候(只能遍历List体系的集合),可以删除,但是在删除过程中索引会改变, size也会发生改变,所以容易出现漏删的情况。

解决:索引–,代码片段如下:

ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
for(int i = 0; i < list.size(); i++) {
    if("b".equals(list.get(i))) {
        list.remove(i--);	//通过索引删除元素
    }
}

2)迭代器在遍历集合的时候 Iterator(可以遍历任何单列集合),不可以通过集合操作元素,否则会报并发修改异常。只能通过迭代器自身来对元素进行操作,如果是删除:可以用Iterator 也可以用ListIterator 因为他们里面都有remove();如果是添加:只能使用ListIterator,因为只有ListIterator里面有add()
代码片段如下:

ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
Iterator<String> it = list.iterator();
while(it.hasNext()) {
    if("b".equals(it.next())) {
        //list.remove("b");	//不能用集合的删除方法,因为迭代过程中如果集合修改会出现并发修改异常
        it.remove();		//让迭代器自己来删除元素
    }
}

3)增强for循环遍历集合的时候(可以遍历任何单列集合),由于底层就是调用的迭代器,所以不能删除,只能遍历。代码片段如下:

ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
for (String string : list) {
    if("b".equals(string)) {
        list.remove("b");	//运行报错,并发修改异常,增强for循环底层用的是迭代器 所以不能在迭代器过程中让集合来删除元素,如果用迭代器自己来删除 ,哪有迭代器来让你使用呢?,在底层呢 你又看不到
    }
}
System.out.println(list);

可变参数
格式:修饰符 返回值类型 方法名(数据类型 … 变量名){}
注意:

  1. 可变参数是JDK1.5后出现的新特性
  2. 可变参数其实是一个数组,所以调用带有可变参数的方法的时候,可以传入一个相同类型的数组
  3. 有多个参数的时候,可变参数放到最后

代码演示:

public class Demo3_ChangeableArgs {
	public static void main(String[] args) {
		int[] arr = {11,22,33,44,55};
		print();			//调用的时候 可以不传入参数
		print(arr);			//调用的时候 可以传入一个数组,因为可变参数的底层就是使用的数组
		print(11,22,55);		//调用的时候 可以传入多个参数		
	}

    public static void print(int ... arr) {	//可变参数其实是一个数组
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
    public static void show(String s , int ... arr) {	//有多个参数的时候,可变参数放到最后

    }
    /*
		public static void method(int ... arr , String s) {	//编译报错 有多个参数的时候,可变参数放到最后

		}*/
}

//可变参数的应用
public class Demo4_ChangeableArgs {
    public static void main(String[] args) {	
        //求两个数的最大值,我需要定义一个,含两个参数的方法max(int a , int b)
        int big = max(5,6);
        //假如现在需求变了,我想求三个数的最大值,那么我需要定义一个含三个参数的方法 max(int a , int b , int c)
        int big1 = max(5,6,10);

        //假如现在需求又变了,我想求四个数的最大值,难道我就再继续定义一个含有四个参数的方法 max(int a , int b , int c , int d)吗? 这样太麻烦了, 解决方案就是 用可变参数
        int big2 = max(11,432,7,87,23);
    }

    //求两个数的最大值
    public static int max(int a , int b) {
        return a>b?a:b;
    }

    //求三个数的最大值
    public static int max(int a , int b , int c) {
        return a>b ? (a>c?a:c) : (b>c?b:c);
    }

    //求任意个数的最大值
    public static void max(int ... arr) {	//可变参数其实是一个数组
        int a = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if(arr[i]> a){
                a = arr[i]
            }
        }
        return a;
    }
}
集合和数组之间的转换

Arrays工具类的asList(T … t):将数组转成集合(该方法用的可变参数)
注意:

1)返回一个长度固定的集合,可以改和查,不能增和删,也就是改变其长度的操作都不可以做。

2)将数组转换成集合,数组必须是引用数据类型。

Collection中toArray(T[] a)泛型版的集合转数组:

T[] 明确成什么样的数组 toArray(T[] a)方法就返回什么类型的数组

注意:当集合转换数组时,数组长度如果是小于等于集合的size时,转换后的数组长度等于集合的size;如果数组的长度大于了size,分配的数组长度就和你指定的长度一样。

好了今天就先说到这了,想了解更多学习知识,请关注微信公众号“阿Q说”,获取更多学习资料吧!你也可以后台留言说出你的疑惑,阿Q将会在后期的文章中为你解答。每天学习一点点,每天进步一点点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿Q说代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值