zoukankan      html  css  js  c++  java
  • 零基础学习java------day14-----泛型,foreach,可变参数,数组和集合间的转换,Set,Map,

    1.泛型(jdk1.5以后出现)

    https://www.cnblogs.com/lwbqqyumidi/p/3837629.html#!comments

    1)为什么要用泛型?

      限制集合,让它只能存储某种类型的元素,如果不限制,集合(默认Object类型)中想存什么就存什么,这样在取元素的时候就会面临大量强制类型转换,这就很可能出现转换异常,为了解决这个问题,jdk1.5以后就出现泛型

      当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。因此,当我们取出集合元素时需要人为的强制类型转化到具体的目标类型,这就很容易很容易出现“java.lang.ClassCastException”异常

    (2)泛型概述

      泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变化量话参数,此时类型也定义成参数形式(可称之为类型形参),然后在使用/调用时传入具体的类型(类型实参),一般用"<E>"表示。泛型只在编译时有效,在生成的.class文件中,会把泛型擦除掉。

    (3)泛型定义

    a  定义在类上

     若类在定义时没有加泛型时,则在创建对象时,不能使用泛型,如下图

    此时Box定义时加上泛型,如下

    public class GenericDemo {
        public static void main(String[] args) {
            Box<Integer> box = new Box<>(2);  //右边的尖括号内不需要写具体的可类型,jdk.7以后会根据左边自动识别出类型是什么
        }
    }
    class Box<T>{
        T t;              // T的类型是什么由创建对象时确定,如此处T就是Integer类型
        public Box(T t) {
            this.t = t;
        }
        public T getT() {
            return t;
        }
    }

    注意,类在创建对象时,不加泛型,默认是Object类型

    b  定义在方法上(不常用)

    用法:方法的逻辑相同,只是数据类型不同,这个时候使用反省方法,泛型写在返回值之前,以Collections中sort方法的源码为例

    public static <T extends Comparable<? super T>> void sort(List<T> list) {
            list.sort(null);
        }

    用了泛型后,sort方法中List中的参数类型就可以不同

    public class GenericDemo {
        public static void main(String[] args) {
            String str = cast("aaa");
        }
        public static<E> E cast(Object o) {
            return (E)o;// 强制类型转换,向下转型
        }
    }

    c. 泛型定义在接口上

    interface A<E>{
        public void test(E e);
    }
    // 如果实现的接口没有指定具体的类型,则子类必须泛型下去
    class B<E> implements A<E>{
        public void test(E e) {
            
        }
    }
    // 如果实现的接口给定了具体的类型,子类中用到泛型的地方都必须使用该类型
    class C implements A<String>{
    
        @Override
        public void test(String e) {
                
        }    
    }

     (4)泛型通配符

    泛型通配符:

        泛型通配符<?>

            任意类型,如果没有明确,那么就是Object以及任意的java类了

          ?extends E

            向下限定,E及其子类

          ?super E

            向上限定,E及其父类

      注意:泛型的通配值只能用在=的左边或者是参数列表上

    public class GenericDemo2 {
        public static void main(String[] args) {
            Collection<?> c1 = new ArrayList<Animal>();
            Collection<?> c2 = new ArrayList<Dog>();
            Collection<?> c3 = new ArrayList<Cat>();
            Collection<?> c4 = new ArrayList<Object>();
            Collection<? extends Animal> c5 = new ArrayList<Animal>();
            Collection<? extends Animal> c6 = new ArrayList<Dog>();
            Collection<? extends Animal> c7 = new ArrayList<Cat>();
            //Collection<? extends Animal> c8 = new ArrayList<Object>();报错
            Collection<? super Animal> c9 = new ArrayList<Animal>();
            // Collection<? super Animal> c10 = new ArrayList<Dog>();报错
            // Collection<? super Animal> c11 = new ArrayList<Cat>();报错
            Collection<? super Animal> c12 = new ArrayList<Object>();
        }
    }
    
    class Animal {}
    class Dog extends Animal {}
    class Cat extends Animal {}

    2. foreach(增强for循环)

      简化数组和Collection集合的遍历

      格式:

         for(元素数据类型 元素名 :数组或者Collection集合){对元素进行你自己的操作}

      好处:简化遍历

      注意事项:增强for的目标要判断是否为null

    数组遍历

    public class ForeachClass {
        public static void main(String[] args) {
            String[] str = new String[] {"",""};//当此处的数组为null时就会报java.lang.NullPointerException错误,所以要加验证,如下集合例子
            for(String a:str) {
                System.out.println(a);
            }
        }
    }

    集合的遍历

    public class ForeachClass {
        public static void main(String[] args) {
            List<Person> ps = new ArrayList<>();
            ps.add(new Person("张三",27));
            ps.add(new Person("张一",17));
            ps.add(new Person("李四",37));
            ps.add(new Person("老王",67));
            ps.add(new Person("小红",25));
            if(ps!=null && ps.size()>0) {
                for(Person p:ps) {
                    System.out.println(p);
                }
            }
        }
    }
    class Person{
        String name;
        int age;
        public Person(String name, int age) {
            super();
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }
        
    }
    View Code

    3. 可变参数

      定义方法的时候不知道该定义多少个参数

    格式:

      修饰符  返回值类型  方法名(数据类型···  变量名)

    注意:

      这里的变量其实是一个数组

      如果一个方法有可变参数,并且有多个参数,那么,可变参数必须是最后一个(若放前面的话,不能确定哪个参数时不可变参数)

    案例

    public class ChangeableParamDemo {
        public static void main(String[] args) {
            System.out.println(getSum(1,2,33));    
        }
        public static int getSum(int b, int...a) {  //此变量a为数组
            int sum = 0;
            System.out.println(b);
            for(int i=0;i<a.length;i++) {
                sum += a[i];
            }
            return sum;    
        }
    }
    // 运行结果:
    1
    35

    4. 数组和集合间的转换

      1.集合转数组;

         toArray(collection):   得到   Object[ ]

      2.数组转集合:

    案例

    public class ArrayAndCollection {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("老王");
            list.add("小明");
            //1 集合转数组
            Object[] o = list.toArray();
            System.out.println(o);
            //2 数组转集合
            String[] str = {"1","2"}; 
            List<String> list1 = Arrays.asList(str);
            System.out.println(list1 instanceof List);//true
        } 
    }

    注意,使用alist得到的集合是不能进行add和remove操作的(只能是可读的集合,

    原因:此处asList返回的是一个ArrayList对象,但这个ArrayList是Arrays里面的内部类,这个类中没有实现增加和删除的方法   

    如果非要操作,需要创建一个新的集合,把它传入到构造方法中,如下

    Integer[] arr = {1,2}; 
    List<Integer> list1 = Arrays.asList(arr);
    List<Integer> list2 = new ArrayList<>(list1);
    list2.add(100);
    System.out.println(list2);//[1, 2, 100]

    5.Set

    (1)

    特点:Set的元素时无序的(不能使用索引操作元素),元素不可重复

    collection:

       List():  有序的,元素可重复

             ArrayList

           LinkedList:特有方法(增删,获取集合首个和最后一个元素)

         Set(): 无序的(不能使用索引操作元素),元素不能重复

          HashSet:无法保证存入和取出的顺序

          LinkedHashSet:可以保证存入和取出的顺序(链表实现)

          TreeSet:有序的(可以对元素排序)

    不可重复性的原理:

      是由hashCode和equals方法保证的

      存放元素的时候,先求出元素的hashCode,如果集合中没有这样的hashCode值,说明该元素在集合中不存在,可以存;有这样的hashCode,再比较equals:如果为true,集合中已经存在噶元素,则不存,如果为false,则可以存。

     案例

    public class SetDemo {
        public static void main(String[] args) {
            Set<String> set = new HashSet<>();
            set.add("小猫警长");
            set.add("黑猫警长");
            set.add("白猫警长");
            set.add("花猫警长");
            set.add("白猫警长");
            set.add("花猫警长");
            set.add("黑猫警长");
            set.add("红猫警长");
            System.out.println(set);
        }
    }
    // 运行结果:[黑猫警长, 红猫警长, 白猫警长, 花猫警长, 小猫警长]
    View Code

    可见存入的顺序并不有序,若想有序可以使用LinkedHashSet创建对象

    (2)Set的遍历(三种方法)

    第一种:数组

    public class SetDemo {
        public static void main(String[] args) {
            Set<String> set = new HashSet<>();
            set.add("小猫警长");
            set.add("黑猫警长");
            set.add("白猫警长");
            set.add("花猫警长");
            set.add("红猫警长");
            Object[] array = set.toArray();
            for(Object s:array) {
                System.out.println(s);
            }
       }
    }

    第二种:迭代器

    Iterator<String> it = set.iterator();
    while(it.hasNext()) {
        System.out.println(it.next());
    }

    第三种(增强for循环)

    for(String str :set) {
        System.out.println(str);
    }

    练习

    1. 使用LinkedHashSet填写一个程序,获取10个1至20的随机数,要求随机数不能重复

    public class TenNum {
        public static void main(String[] args) {
            Set<Integer> set = new LinkedHashSet<>();
            Random r = new Random();
            while(set.size()<10) {
                int num = r.nextInt(20)+1;
                set.add(num);
            }
            System.out.println(set);
        }
    }

    2. 使用集合去重

    public class SetQuChong {
        public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(1);
        list.add(2);
        list.add(2);
        List<Integer> list1 = distinct(list);
        System.out.println(list1);
        }
        public static List<Integer> distinct(List<Integer> list){
            Set<Integer> set = new HashSet<>();
            set.addAll(list);
            list.clear();
            list.addAll(set);
            return list;
        }
    }
    // 运行结果:[1,2]
    View Code

    6. Map

    6.1 概述

      双列集合的跟接口;将键映射到值的对象;一个映射不能包含重复的键,每个键最多只能映射到一个值。

    Map接口和Collection接口的不同:

      Map是双列的,Colection是单列的

      Map的键唯一(值可以不唯一),Collection的子体系只有Set是唯一的

    6.2 Map接口的成员方法

    V put(K key,V value) 添加元素(返回值是Key上一次对应的Value)
    V remove(Object key) 移除key对应的键值对(返回值是value)
    void clear() 清空map
    boolean containsKey(Object key) 是否包含key
    boolean containsValue(Object value) 是否包含value
    boolean isEmpty() 是否为空
    int size() 键值对的个数

    V put(K key,V value) 添加元素(返回值是Key上一次对应的Value)

    public class MapDemo {
        public static void main(String[] args) {
            Map<String,String> map = new HashMap<>();
            String re = map.put("a","啊,五环,你比四环多一环");
            System.out.println(re);
            String re1 = map.put("a","啊,四环,你比五环少一环");
            System.out.println(re1);
        }
    }
    //运行结果:
    null
    啊,五环,你比四环多一环

    由结果可知,put的返回值为当次被覆盖的内容(第一次打印的结果为null,相当于第一次添加值将null覆盖)

    V remove(Object key) 移除key对应的键值对(返回值是被移除键值对中的value)

    System.out.println(map);//{a=啊,四环,你比五环少一环}
    String re2 = map.remove("a");
    System.out.println(re2);//啊,四环,你比五环少一环

    get(key) 方法(可用于遍历),返回值为key所对应的值

    System.out.println(map);//{a=啊,四环,你比五环少一环}
    String re3 = map.get("a");
    System.out.println(re3);//啊,四环,你比五环少一环

    6.3 Hashmap的遍历

    第一种  keySet  获取所有key

    public class MapDemo {
        public static void main(String[] args) {
            Map<Integer,String> map = new HashMap<>();
            map.put(1, "小明");
            map.put(2, "小红");
            map.put(3, "小王");
            map.put(4, "小李");
            Set<Integer> keySet = map.keySet();
            for(Integer key:keySet) {
                System.out.println("key:"+key+",value:"+map.get(key));
            }
        }
    }

    第二种  entrySet(获取键值对)

    Set<Entry<Integer, String>> entrySet = map.entrySet();
    for (Entry<Integer, String> entry:entrySet) {
      System.out.println("key:"+entry.getKey()+",value:"+entry.getValue());
    }

    使用迭代器实现:

    
    
    Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
    while(it.hasNext()) {
        System.out.println(it.next());
        System.out.println("key:"+next.getKey()+",value:"+next.getValue());
    }

    第三种  values:只能得到所有的value

    Collection<String> values = map.values();
    for (String v :values) {
        System.out.println(v);
    }

    6.4 HashMap的实现原理

    使用散列表(由数组和链表组成)或哈希表来实现的(效率高)

    数组+链表:元素是链表的数组(主体是数组)

    练习:统计一个字符串中各个字符出现的次数

    public class StrTimes {
        public static void main(String[] args) {
            Scanner sc= new Scanner(System.in);
            System.out.println("请输入一个字符串");
            String str = sc.nextLine();
            // 创建map,用来存储数据
            Map<Character, Integer> map = new HashMap<>();
            // 遍历获取每一个字符
            for(int i=0;i<str.length();i++) {
                char ch = str.charAt(i);
                //用ch做key去map中查询是否有值
                Integer value = map.get(ch);
                if(value == null) {
                    map.put(ch, 1);
                }else {
                    value++;
                    map.put(ch,value);
                }
            }
            Set<Character> keySet = map.keySet();
            for(Character c:keySet) {
                System.out.println("字符"+c+"的次数:"+map.get(c));
            }
        }
    }
  • 相关阅读:
    linux 常用操作指令(随时更新)
    Spring @Scheduled应用解析
    H5的FormData对象完成ajax上传文件multiFile
    微服务的4个设计原则和19个解决方案
    微服务实战(六):如何做好服务拆分?
    微服务实战(五):微服务化之缓存的设计
    微服务实战(四):微服务化之无状态化与容器化
    微服务实战(三):以MySQL为例,从原理上理解那些所谓的数据库军规
    微服务实战(二):微服务的接入层设计与动静资源隔离
    微服务实战(一):微服务化的基石——持续集成
  • 原文地址:https://www.cnblogs.com/jj1106/p/11382080.html
Copyright © 2011-2022 走看看