java基础入门

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

2019-02-20  本文已影响20人  阿Q说代码

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<Integer>(); //当右边的泛型是不确定时,左边可以指定为?
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将会在后期的文章中为你解答。每天学习一点点,每天进步一点点。

上一篇下一篇

猜你喜欢

热点阅读