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 + "]";
} }

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);
}
}
// 运行结果:[黑猫警长, 红猫警长, 白猫警长, 花猫警长, 小猫警长]

可见存入的顺序并不有序,若想有序可以使用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]

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));
}
}
}

零基础学习java------day14-----泛型,foreach,可变参数,数组和集合间的转换,Set,Map,的更多相关文章

  1. 音乐出身的妹纸,零基础学习JAVA靠谱么

    问:表示音乐出身的妹纸一枚  某一天突然觉得身边认识的是一群程序员   突然想 要不要也去试试... 众好友都觉得我该去做个老师,可是我怕我会误人子弟,祸害祖国下一代..... 要不要 要不要 学Ja ...

  2. 总结了零基础学习Java编程语言的几个基础知识要点

    很多Java编程初学者在刚接触Java语言程序的时候,不知道该学习掌握哪些必要的基础知识.本文总结了零基础学习Java编程语言的几个基础知识要点. 1先了解什么是Java的四个方面   初学者先弄清这 ...

  3. 中国MOOC_零基础学Java语言_第5周 数组_1多项式加法

    第5周编程题 查看帮助 返回   第5周编程题 依照学术诚信条款,我保证此作业是本人独立完成的. 温馨提示: 1.本次作业属于Online Judge题目,提交后由系统即时判分. 2.学生可以在作业截 ...

  4. 零基础学Java(13)方法参数

    前言 首先回顾一下在程序设计语言中关于如何将参数传递给方法的一些专业术语.按值调用表示方法接收的是调用者提供的值.而按引调用表示方法接收的是调用者提供的变量地址.方法可以修改按引用传递的变量的值,而不 ...

  5. 中国MOOC_零基础学Java语言_第5周 数组

    第5周 数组 5.1 数组 5.2 数组计算 public class Main { public static void main(String[] args) { for (int i = 1; ...

  6. Effective Java 第三版——32.合理地结合泛型和可变参数

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  7. 零基础学Java第四节(字符串相关类)

    本篇文章是<零基础学Java>专栏的第四篇文章,文章采用通俗易懂的文字.图示及代码实战,从零基础开始带大家走上高薪之路! String 本文章首发于公众号[编程攻略] 在Java中,我们经 ...

  8. 如何从零基础学习VR

    转载请声明转载地址:http://www.cnblogs.com/Rodolfo/,违者必究. 近期很多搞技术的朋友问我,如何步入VR的圈子?如何从零基础系统性的学习VR技术? 本人将于2017年1月 ...

  9. 【零基础学习iOS开发】【转载】

    原文地址:http://www.cnblogs.com/mjios/archive/2013/04/24/3039357.html 本文目录 一.什么是iOS 二.主流手机操作系统 三.什么是iOS开 ...

随机推荐

  1. hdu 5172 GTY's gay friends(线段树最值)

    题意: GTY有n个朋友,站成一排,每个人有一个特征值ai. 有m个询问.每次询问给两个数L,R.问你[L,R](即aL...aR)是否是1..(R-L+1)的一个全排列. 是输出YES,否则输出NO ...

  2. shell 脚本静默安装oracle11g

    以下脚本的手动安装连接:  https://www.cnblogs.com/leihongnu/p/12698593.html [ #/bin/bash#安装日志touch /root/message ...

  3. Linux&C———进程间通信

    管道和有名管道 消息队列 共享内存 信号 套接字 由于进程之间的并不会像线程那样共享地址空间和数据空间,所以进程之间就必须有自己特有的通信方式,这篇博客主要介绍自己了解到的几种进程之间的通信方式,内容 ...

  4. 数据代理Object.defineProperty()

    数据代理: 通过一个对象代理对另一个对象中属性的操作(读/写) 数据代理 Object.defineProperty() Object.defineProperty() 方法会直接在一个对象上定义一个 ...

  5. PTA 7-2 邻接表创建无向图 (20分)

    PTA 7-2 邻接表创建无向图 (20分) 采用邻接表创建无向图G ,依次输出各顶点的度. 输入格式: 输入第一行中给出2个整数i(0<i≤10),j(j≥0),分别为图G的顶点数和边数. 输 ...

  6. 大一C语言学习笔记(4)---自省篇

    博主"曾经"做过的傻事: #你有的*没打全 #你用/的时候没考虑()是一对的 #printf随后加\n #所有变量只要用,就一定要定义数据类型 #sqrt()代表根号 #inclu ...

  7. 树莓派4b安装Ubuntu20.04

    树莓派4b安装Ubuntu20.04 下载Ubuntu20.04镜像 下载地址 安装Raspberry Pi Imager 下载地址 烧录系统 打开Raspberry Pi Imager,选择自己刚刚 ...

  8. 使用Typora+PicGo配置Gitee图床

    1.图床痛点 通常我们用 Typora 写 Markdown 文档,对于文档里面的图片,如果不使用图床,图片都是存放在本地,如果把文档复制到别的地方,还得额外复制图片,特别麻烦. 为了解决这种问题,一 ...

  9. python实现高斯滤波

    一,定义 核是:3 *3     均值滤波 二,高斯函数 Y方向的方差与X方向的一致.处理后图像看起来更模糊(滤波明显)的话,核要更大. (三)代码实现 (四)核计算 (五)图像产生高斯噪声循环代码实 ...

  10. [bzoj1738]发抖的牛

    二分答案,每一头牛向所有在规定时间内能走到的牛棚连inf的边,每一个源点向牛连牛数量的边,每一个牛棚向汇点连牛棚容量的边,能满流则意味着这个答案可行,否则不可行. 1 #include<bits ...