第十八天 集合-泛型&list接口&set接口【面试+工作】
第18天 集合
泛型用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数传递。
泛型是数据类型的一部分,我们将类名与泛型合并一起看做数据类型。
泛型的定义:定义泛型可以在类中预支地使用未知的类型。
泛型的使用:一般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。
我们在集合中会大量使用到泛型,这里来完整地学习泛型知识。
泛型,用来灵活地将数据类型应用到不同的类、方法、接口当中。将数据类型作为参数进行传递。
定义格式:修饰符 class 类名<代表泛型的变量> { }
class ArrayList<E>{
public boolean add(E e){ }
public E get(int index){ }
}
使用格式:创建对象时,确定泛型的类型
此时,变量E的值就是String类型
class ArrayList<String>{
public boolean add(String e){ }
public String get(int index){ }
}
此时,变量E的值就是Integer类型
class ArrayList<Integer>{
public boolean add(Integer e){ }
public Integer get(int index){ }
}
定义格式:修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }
public <T> T[] toArray(T[] a){ }
//该方法,用来把集合元素存储到指定数据类型的数组中,返回已存储集合元素的数组
使用格式:调用方法时,确定泛型的类型
ArrayList<String> list = new ArrayList<String>();
String[] arr = new String[100];
String[] result = list.toArray(arr);
此时,变量T的值就是String类型。变量T,可以与定义集合的泛型不同
public <String> String[] toArray(String[] a){ }
ArrayList<String> list = new ArrayList<String>();
Integer[] arr = new Integer[100];
Integer [] result = list.toArray(arr);
此时,变量T的值就是Integer类型。变量T,可以与定义集合的泛型不同
public <Integer> Integer[] toArray(Integer[] a){ }
定义格式:修饰符 interface接口名<代表泛型的变量> { }
public interface Iterator<E> {
public abstract E next();
}
使用格式:
1、定义类时确定泛型的类型
public final class Scanner implements Iterator<String> {
public String next(){ }
}
此时,变量E的值就是String类型。
2、始终不确定泛型的类型,直到创建对象时,确定泛型的类型
Collection<String> list = new ArrayList<String>();
Iterator<String> it = list.iterator();
此时,变量E的值就是String类型。
public interface Iterator<String> {
public abstract String next();
}
}
在JDK1.5出现前,使用Object代表任意类型,但在使用时,涉及到了强转的麻烦。泛型替代了Object来代表任意类型。
泛型在编译时会擦除:泛型仅用来在编译期限制、方便程序员的操作,实际上真正编译后的.class中是没有泛型的,其中仍然使用的为Obejct类,通过类似多态的方式完成任意某个类型的指定。
当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
定义:(查看ArrayList的构造方法)无法在类中使用
使用:调用方法时可以给予任意类型。参照Arraylist的构造方法
? extends E代表只要是E类型的子类即可
? super E代表只要是E类型的父类即可
/*
* 泛型通配符?,代表任意的数据类型
*
* 定义:(查看ArrayList的构造方法)无法在类中使用
*
* 使用:调用方法时可以给予任意类型。参照Arraylist的构造方法
* public ArrayList(Collection<? extends E> c)
* 为了便于?的理解,我们将以上方法重写为public ArrayList(ArrayList<? extends E> c)
*
* 该方法的意思:创建集合对象A时,给于另外一个集合对象B作为参数,则创建好的集合A中包含了集合B中的元素
*
* ? extends E代表只要是E类型的子类即可
* ? super E代表只要是E类型的父类即可
*/
public class Demo01 {
public static void main(String[] args) {
//定义集合b,包含3个元素
ArrayList<String> listB = new ArrayList<String>();
listB.add("Jack");
listB.add("Rose");
listB.add("Trump");
//使用集合b创建集合a
ArrayList<Object> listA = new ArrayList<Object>(listB);
listA.add("Obama");
//观察集合A
System.out.println(listA);
}
泛型的好处:
1.提高了程序的安全性
2.将运行期遇到的问题转移到了编译期
3.省去了类型强转的麻烦
泛型的常见应用:
1.泛型类
2.泛型方法
3.泛型接口
ArrayList:底层数据结构是数组结构。线程不安全的。所以ArrayList的出现替代了Vector。增删慢,查找快。
LinkedList:底层是链表数据结构。线程不安全的,同时对元素的增删快,查找慢。
Vector:底层数据结构是数组结构。jdk1.0版本。线程安全的。无论增删还是查询都非常慢,已被ArrayList替代。
List接口下有很多个集合,它们存储元素所采用的结构方式是不同的,这样就导致了这些集合有它们各自的特点,供给我们在不同的环境下进行使用。数据存储的常用结构有:堆栈、队列、数组、链表。我们分别来了解一下:
void add(int index, E element) //指定索引添加元素
E remove(int index) //移除指定索引处元素
E get(int index) //获取指定索引元素
E set(int index, E element) //修改指定索引元素
List<E> subList(int fromIndex, int toIndex) //截取指定索引子集
int indexOf(Object o) //返回指定元素索引位置
import java.util.ArrayList;
import java.util.List;
/*
* List 方法
*
* void add(int index, E element) //指定索引添加元素
*/
public class Demo {
public static void main(String[] args) {
//fun3();
//fun2();
//fun();
}
private static void fun3() {
List <String > al = new ArrayList<>();
al.add("111");// 添加 Collection中 继承来的
al.add("222");
al.add("333");
al.add("444");
System.out.println(al);
al.set(2, "6666");
System.out.println(al);
List<String> subList = al.subList(1, 4);
System.out.println(subList);
int indexOf = subList.indexOf("444");
System.out.println(indexOf);
}
private static void fun2() {
List <Integer > al = new ArrayList<>();
al.add(1);
al.add(2);
al.add(3);
al.add(4);
al.remove(2);
System.out.println(al);
}
private static void fun() {
List <String > al = new ArrayList<>();
al.add("111");// 添加 Collection中 继承来的
al.add("222");
al.add("333");
al.add("444");
al.add(2, "666");
al.add(5, "999");
al.add(6, "000999");
System.out.println(al);
al.remove(6);
System.out.println(al);
}
}
ListIterator<E> listIterator() 注意:用于应对并发修改异常的返回迭代器方法与迭代器
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/*
* ListIterator : Iterator 子接口.
*
* Collection 是得不到ListIterator , 因为 List 专属的.
*
* add添加方法 比较常用.
*/
public class Demo2 {
public static void main(String[] args) {
//fun();
List c = new ArrayList<>();
c.add("孙悟空");
c.add("白骨精");
c.add("唐三藏");
c.add("八戒");
ListIterator li = c.listIterator();
while (li.hasNext()) {
Object object = (Object) li.next();
if (object.equals("白骨精")) {
li.add("白龙马");
}
}
System.out.println(c);
ListIterator listIterator = c.listIterator();
listIterator.next();
System.out.println(listIterator.hasPrevious());
}
private static void fun() {
Collection c = new ArrayList<>();
c.add("孙悟空");
c.add("白骨精");
c.add("唐三藏");
c.add("八戒");
//遍历 集合, 如果 包含 白骨精 ,你就添加一个 白龙马.
Iterator iterator = c.iterator();
while (iterator.hasNext()) {
Object object = (Object) iterator.next();
if (object.equals("白骨精")) {
c.add("白龙马"); //ConcurrentModificationException
}
}
System.out.println(c);
}
}
ArrayList底层数据结构是数组结构。线程不安全的,所以运行速度快,ArrayList的出现替代了Vector。增删慢,查找快,由于日常开发中使用最多的功能为查询数据,遍历数据,所以ArrayList是最常用的集合。目前市面上许多程序员开发时并不严谨,非常随意地使用ArrayList完成任何需求,这种用法是不提倡的。
LinkedList集合数据存储的结构是链表结构。方便元素添加、删除的集合。实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。如下图
LinkedList是List的子类,List中的方法LinkedList都是可以使用,这里就不做详细介绍,我们只需要了解LinkedList的特有方法即可。在开发时,LinkedList集合也可以作为堆栈,队列的结构使用。
方法演示:
LinkedList<String> link = new LinkedList<String>();
//添加元素
link.addFirst("abc1");
link.addFirst("abc2");
link.addFirst("abc3");
//获取元素
System.out.println(link.getFirst());
System.out.println(link.getLast());
//删除元素
System.out.println(link.removeFirst());
System.out.println(link.removeLast());
while(!link.isEmpty()){ //判断集合是否为空
System.out.println(link.pop()); //弹出集合中的栈顶元素
}
Vector:我们可以将其理解为版本旧的、安全的、效率低的ArrayList,Vector中提供了一个独特的取出方式,就是枚举Enumeration。此接口Enumeration的功能与 Iterator 接口的功能是类似的。
有兴趣的同学可以自己了解:
public E elementAt(int index) / get(index )
public E firstElement()
public E lastElement()
public void setElementAt(E obj, int index) set(index,obj)
public void removeElementAt(int index)及其他删除 remove(index)
public Enumeration<E> elements()
import java.util.Enumeration;
import java.util.Vector;
/*
* Vector : 数组结构,单线程的 ArrayList.
*/
public class Demo2 {
public static void main(String[] args) {
Vector<String > vector = new Vector<>();
vector.addElement("111");
vector.addElement("222");
vector.addElement("444");
vector.addElement("333333");
// 获取 枚举.
Enumeration<String> elements = vector.elements();
while (elements.hasMoreElements()) {
String nextElement = elements.nextElement();
System.out.println(nextElement);
}
}
}
查阅Set集合的API介绍,通过元素的equals方法,来判断是否为重复元素,它是个不包含重复元素的集合。Set集合取出元素的方式可以采用:迭代器、增强for。
Set集合有多个子类,这里我们介绍其中的HashSet、LinkedHashSet这两个集合。
查阅HashSet集合的API介绍:此类实现Set接口,由哈希表支持(实际上是一个 HashMap集合)。HashSet集合不能保证的迭代顺序与元素存储顺序相同。
HashSet集合,采用哈希表结构存储数据,保证元素唯一性的方式依赖于:hashCode()与equals()方法。
什么是哈希表呢?
哈希表底层使用的也是数组机制,数组中也存放对象,而这些对象往数组中存放时的位置比较特殊,当需要把这些对象给数组中存放时,那么会根据这些对象的特有数据结合相应的算法,计算出这个对象在数组中的位置,然后把这个对象存放在数组中。而这样的数组就称为哈希数组,即就是哈希表。
当向哈希表中存放元素时,需要根据元素的特有数据结合相应的算法,这个算法其实就是Object类中的hashCode方法。由于任何对象都是Object类的子类,所以任何对象有拥有这个方法。即就是在给哈希表中存放对象时,会调用对象的hashCode方法,算出对象在表中的存放位置,这里需要注意,如果两个对象hashCode方法算出结果一样,这样现象称为哈希冲突,这时会调用对象的equals方法,比较这两个对象是不是同一个对象,如果equals方法返回的是true,那么就不会把第二个对象存放在哈希表中,如果返回的是false,就会把这个值存放在哈希表中。
总结:保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。
给HashSet中存储JavaAPI中提供的类型元素时,不需要重写元素的hashCode和equals方法,因为这两个方法,在JavaAPI的每个类中已经重写完毕,如String类、Integer类等。
public class HashSetDemo {
public static void main(String[] args) {
//创建HashSet对象
HashSet<String> hs = new HashSet<String>();
//给集合中添加自定义对象
hs.add("zhangsan");
hs.add("lisi");
hs.add("wangwu");
hs.add("zhangsan");
//取出集合中的每个元素
Iterator<String> it = hs.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
}
}
输出结果如下,说明集合中不能存储重复元素:
wangwu
lisi
zhangsan
给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一
public class Student {
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if(!(obj instanceof Student)){
System.out.println("类型错误");
return false;
}
Student other = (Student) obj;
return this.age == other.age && this.name.equals(other.name);
}
}
public class HashSetDemo {
public static void main(String[] args) {
//创建HashSet对象
HashSet hs = new HashSet();
//给集合中添加自定义对象
hs.add(new Student("zhangsan",21));
hs.add(new Student("lisi",22));
hs.add(new Student("wangwu",23));
hs.add(new Student("zhangsan",21));
//取出集合中的每个元素
Iterator it = hs.iterator();
while(it.hasNext()){
Student s = (Student)it.next();
System.out.println(s);
}
}
}
输出结果如下,说明集合中不能存储重复元素:
Student [name=lisi, age=22]
Student [name=zhangsan, age=21]
Student [name=wangwu, age=23]
ArrayList的contains方法会使用调用方法时,传入的元素的equals方法依次与集合中的旧元素所比较,从而根据返回的布尔值判断是否有重复元素。此时,当ArrayList存放自定义类型时,由于自定义类型在未重写equals方法前,判断是否重复的依据是地址值,所以如果想根据内容判断是否为重复元素,需要重写元素的equals方法。
Set集合不能存放重复元素,其添加方法在添加时会判断是否有重复元素,有重复不添加,没重复则添加。
HashSet集合由于是无序的,其判断唯一的依据是元素类型的hashCode与equals方法的返回结果。规则如下:
先判断新元素与集合内已经有的旧元素的HashCode值
所以,使用HashSet存储自定义类型,如果没有重写该类的hashCode与equals方法,则判断重复时,使用的是地址值,如果想通过内容比较元素是否相同,需要重写该元素类的hashcode与equals方法。
hashCode方法重写规则:将该对象的各个属性值hashCode相加即是整个对象的HashCode值。如果是基本类型,类似int,则直接返回int值就是该属性的hash值,如果是引用类型,类似String,就调用该成员变量的hashCode方法返回该成员变量hash值。这样可以根据对象的内容返回hashCode值,从而可以根据hashCode判断元素是否唯一。
但是由于在一些”碰巧的”情况下,可能出现内容不同但hashCode相同的情况,为了避免这些情况,我们加入一些干扰系数。
可是加入干扰系数后,仍会出现一些”碰巧”的情况,所以我们还要进行equals的二次判断。
public class Student {
String name ;
int age;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
// 想要保证 对象的唯一性, 必须重写 equals 和 hashCode();
// (老王, 60 ) , (金莲 ,28 )
// hashCode 而是通过 属性的值计算出来的hashCode
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age; // 91 59
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) // 当前对象与 传参对象 地址 相同 .返回true .
return true;
if (obj == null) //传参对象 为null, 返回 false .
return false;
//当前对象与 传参对象 不一样, 返回false .
if (this.getClass() != obj.getClass()) // getClass() 获取类型
return false;
// 强制转换 .
Student other = (Student) obj;
if (age != other.age) //比较年龄
return false;
if (name == null) { // 比较名字, 我没名,你有名, 返回false
if (other.name != null)
return false;
} else if (!name.equals(other.name)) // 姓名不一样,返回false .
return false;
return true;
}
}
import java.util.HashSet;
/*
* Set : 不包含重复元素的集合.无序 常用 其子类 HashSet .
*
* 你想要使用HashSet保存自定义类型的元素,必须通过重写hashCode和equals方法来保证对象的唯一性.
* 记住: 重写就好使,不重写就挂了. alt + shift + s --> h
*/
public class Demo {
public static void main(String[] args) {
// fun();
HashSet<Student> hashSet = new HashSet<>();
Student student = new Student("金莲", 28);
Student student2 = new Student("小明", 15);
Student student3 = new Student("韩梅梅", 16);
Student student4 = new Student("李雷", 18);
Student student5 = new Student("李雷", 18);
Student student6 = new Student("李雷", 18);
Student student7 = new Student("李雷", 18); // 属性值 全一样, 说明 是同一个对象.
hashSet.add(student);
hashSet.add(student2);
hashSet.add(student3);
hashSet.add(student4);
hashSet.add(student5);
hashSet.add(student6);
hashSet.add(student7);
// 打印 出几个同学?
System.out.println(hashSet);
}
private static void fun() {
HashSet<String> hashSet = new HashSet<>();
// 添加元素
hashSet.add("武大郎");
hashSet.add("武大郎");
hashSet.add("武大郎");
hashSet.add("奥巴马");
hashSet.add("金三胖");
System.out.println(hashSet);
}
}
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
/*
* 需求:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
* 并把最终的随机数输出到控制台。
*/
public class Test {
public static void main(String[] args) {
// 创建Random 对象
Random random = new Random();
//创建集合
HashSet<Integer> hashSet = new HashSet<>();
int count = 0;
// 循环获取,循环添加 , 集合的个数做为条件.
while (hashSet.size() < 10) {
count ++; // 计数
// 调用Random 获取随机数
int i = random.nextInt(20) + 1;
// 添加到集合 , HashSet , 无序,唯一的.
hashSet.add(i);
}
System.out.println(count);
System.out.println("添加完毕,遍历集合");
// 遍历 hashSet
Iterator<Integer> iterator = hashSet.iterator();
while (iterator.hasNext()) {
Integer integer = (Integer) iterator.next();
System.out.print(integer +" ");
}
}
}
public class Student {
String name;
int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return " Student 姓名=" + name + ", 年龄=" + age ;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
// 重写hashCode 和equals
}
import java.util.ArrayList;
import java.util.HashSet;
/*
* 将集合中的重复元素去掉(自定义类 )
ArrayList<Student> list = new ArrayList<>();
Student student = new Student("金莲", 28);
Student student2 = new Student("小明", 15);
Student student3 = new Student("韩梅梅", 16);
Student student4 = new Student("李雷", 18);
Student student5 = new Student("李雷", 18);
Student student6 = new Student("李雷", 18);
list.add(student);
list.add(student2);
list.add(student3);
list.add(student4);
list.add(student5);
list.add(student6);
*/
public class Test2 {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
Student student = new Student("金莲", 28);
Student student2 = new Student("小明", 15);
Student student3 = new Student("韩梅梅", 16);
Student student4 = new Student("李雷", 18);
Student student5 = new Student("李雷", 18);
Student student6 = new Student("李雷", 18);
list.add(student);
list.add(student2);
list.add(student3);
list.add(student4);
list.add(student5);
list.add(student6);
System.out.println(list);
//创建hashSet
HashSet<Student> hashSet = new HashSet<>();
for (Student s : list) {
hashSet.add(s);
}
System.out.println(hashSet);
}
}
按照斗地主的规则,完成洗牌发牌的动作。
具体规则:
使用54张牌打乱顺序
三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。
牌可以设计为一个ArrayList<String>,每个字符串为一张牌。
每张牌由花色数字两部分组成,我们可以使用花色集合与数字集合嵌套迭代完成每张牌的组装。
牌由Collections类的shuffle方法进行随机排序。
将每个人以及底牌设计为ArrayList<String>,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌。
直接打印每个集合。
修改文件编码由GBK修改为UTF-8,因为GBK没有我们要的梅花、方片、黑桃、红桃(♠♥♦♣)等字符。
public class Poker {
public static void main(String[] args) {
//♠♥♦♣
//准备牌
ArrayList<String> poker = new ArrayList<String>();
//花色
ArrayList<String> color = new ArrayList<String>();
color.add("♠");
color.add("♥");
color.add("♦");
color.add("♣");
//数字
ArrayList<String> number = new ArrayList<String>();
for (int i = 2; i <= 10; i++) {
number.add(i+"");
}
number.add("J");
number.add("Q");
number.add("K");
number.add("A");
//完成新牌
for (String thisColor : color) {
for (String thisNumber : number) {
String thisCard = thisColor + thisNumber;
poker.add(thisCard);
}
}
poker.add("小☺");
poker.add("大☻");
//洗牌
Collections.shuffle(poker);
//发牌
//玩家1
ArrayList<String> player1 = new ArrayList<String>();
//玩家2
ArrayList<String> player2 = new ArrayList<String>();
//玩家3
ArrayList<String> player3 = new ArrayList<String>();
//底牌
ArrayList<String> secretCards = new ArrayList<String>();
for (int i = 0; i < poker.size(); i++) {
if(i>=51) {
//最后三张发给底牌
secretCards.add(poker.get(i));
}else {
//剩余牌通过对3取模依次摸牌
if(i%3==0) {
player1.add(poker.get(i));
}else if(i%3==1) {
player2.add(poker.get(i));
}else {
player3.add(poker.get(i));
}
}
}
//看牌
System.out.println(player1);
System.out.println(player2);
System.out.println(player3);
System.out.println(secretCards);
}
}
|- List 可以存储重复元素,有序的(元素存取顺序)
|- ArrayList
|- LinkedList
|- Set 不能存储重复元素,无序的(元素存取顺序)
|- HashSet
|- LinkedHashSet
List:
它是一个有序的集合(元素存与取的顺序相同)
它可以存储重复的元素
Set:
它是一个无序的集合(元素存与取的顺序可能不同)
它不能存储重复的元素
底层数据结构是数组,查询快,增删慢
线程不安全,效率高
底层数据结构是链表,查询慢,增删快
线程不安全,效率高
<数据类型>
泛型可以使用在 类,接口,方法,变量上
A:提高了程序的安全性
B:将运行期遇到的问题转移到了编译期
C:省去了类型强转的麻烦
简化数组和Collection集合的遍历
格式:
for(元素数据类型 变量 : 数组或者Collection集合) {
使用变量即可,该变量就是元素
}
好处:简化遍历
元素唯一不能重复
底层结构是 哈希表结构
元素的存与取的顺序不能保证一致
如何保证元素的唯一的?
重写hashCode() 与 equals()方法
元素唯一不能重复
底层结构是 哈希表结构 + 链表结构
元素的存与取的顺序一致
1. 知识点:自定义类 迭代器 泛型 增强for
要求:会使用迭代器
1) 按以下步骤编写代码:
a) 定义类:Cat,包含以下成员:
成员属性(私有):
名称:
颜色:
年龄:
构造方法:
无参
全参
成员方法:
1).get/set方法;
2).重写toString()方法;内部打印所有属性的值;
b) 在main()方法中,按以下步骤编写代码:
“波斯猫”,“白色”,2
“折耳猫”,“灰色”,1
“加菲猫”,“红色”,3
“机器猫”,“蓝色”,5
遍历集合
1) 使用普通for循环
2) 迭代器(需要指定泛型)
3) 增强for三种方式
泛型的好处:
1.提高了程序的安全性
2.将运行期遇到的问题转移到了编译期
3.省去了类型强转的麻烦
泛型的常见应用:
1.泛型类
2.泛型方法
3.泛型接口
答案:
List<? extends T> :向下限制
List<? super T> :向上限制
? extends T : 代表接收的泛型类型为T类型或T子类类型
? super T :代表接收的泛型类型为T类型或T父类类型
a) 使用迭代器进行遍历,要有泛型
b) 打印出三个手机对象的信息,比如颜色,品牌。
某企业集合:包含各分校元素
每个分校均有班级元素
班级为一个类,类中包括:
所有同学属性
班级班号属性
班级所在楼层属性
同学为一个类,类中包括:
姓名
学号
年龄
说出 ? extends E的含义。使用ArrayList的构造方法:public ArrayList(Collection<? extends E> c) 创建集合,添加元素,迭代集合。
package day08_Test基础练习题;
import java.util.LinkedList;
/*
* 考察LinkedList的push方法
*/
public class Test001 {
public static void main(String[] args) {
//创建一个LinkedList集合
LinkedList<Integer> stack = new LinkedList<Integer>();
//使用push方法
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
stack.push(5);
//打印此时的集合
System.out.println(stack);
}
}
package day08_Test基础练习题;
import java.util.LinkedList;
/*
* 考察LinkedList的add方法
*/
public class Test002 {
public static void main(String[] args) {
//创建LinkedList集合,里面存储的数据类型是String类型,分别将字符串"我","爱","Java","但是","我","更","爱","LOL"添加到集合中,
//使得打印这个集合最终显示为:[我, 爱, Java, 但是, 我, 更, 爱, LOL]
LinkedList<String> list = new LinkedList<String>();
list.add("我");
list.add("爱");
list.add("Java");
list.add("但是");
list.add("我");
list.add("更");
list.add("爱");
list.add("LOL");
//打印这个集合
System.out.println(list);
}
}
package day08_Test基础练习题;
import java.util.LinkedList;
/*
* 考察LinkedList和数组之间的灵活运用
*/
public class Test003 {
/*创建一个LinkedList集合,里面存储的数据类型是String类型;
创建一个String类型的数组,里面的元素为{"我","爱","LOL","但是","我","更","爱","MONEY"};
将String类型的数组里面的元素依次添加到创建的LinkedList集合中
最后打印这个LinkedList集合,显示为:[我, 爱, LOL, 但是, 我, 更, 爱, MONEY]*/
public static void main(String[] args) {
//创建一个LinkedList集合
LinkedList<String> list = new LinkedList<String>();
//创建一个字符串数组
String[] str = {"我","爱","LOL","但是","我","更","爱","MONEY"};
//方法一:使用普通的方式
/*for (int i = 0; i < str.length; i++) {
list.add(str[i]);
}
System.out.println(list);*/
System.out.println("---------------------------------------");
//方法二:使用增强for循环的方式
for (String string : str) {
list.add(string);
}
System.out.println(list);
}
}
A:数据存储和组织方式
B:容器先进后出规则
C:容器先进先出的规则
D:每个元素指向下一个元素
E:一块连续的存储区域
答案说明:数组结构:一块连续的存储区域,查询速度快,添加速度慢链表结构:每个元素指向下一个元素,添加快,查询慢队列结构:容器先进先出的规则栈结构:容器先进后出规则 |
---|
package day08_Test基础练习题;
import java.util.HashSet;
public class Test005 {
public static void main(String[] args) {
HashSet<String> list = new HashSet<>();
String[] str = {"我","爱","编程","但是","我","更","爱","IPHONE"};
for (int i = 0; i < str.length; i++) {
list.add(str[i]);
}
System.out.println(list);
for (String string : str) {
if(string.equals("IPHONE")){
list.remove(string);
//添加元素
list.add("MJ");
}
}
System.out.println("操作过后的元素为:");
System.out.println(list);
}
}
1.编写Person类,有age属性(数据类型是int)和name属性(数据类型是String),且都被private修饰,提供get/set方法,不重写equals方法和hashCode方法
2.编写Test类,在Test类的main方法中定义一个ArrayList集合,集合内存放的元素的数据类型是Person类
思考:是否还能够将重复的对象添加成功?
Person类:
package day08_Test基础练习题;
public class Person {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(int age, String name) {
super();
this.age = age;
this.name = name;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Person [age=" + age + ", name=" + name + "]";
}
}
测试类:
package day08_Test基础练习题;
import java.util.ArrayList;
public class Test006 {
public static void main(String[] args) {
//定义一个ArrayList集合,集合中存储的数据类型是一个类,类的名字叫Person
ArrayList<Person> list = new ArrayList<>();
//使用匿名对象的方式分别将三个Person对象添加到集合中
list.add(new Person(10,"李四"));
list.add(new Person(20,"王五"));
list.add(new Person(30,"小强"));
//创建一个新的对象
Person p4 = new Person(30, "小强");
//打印结果,在Person类中有equals方法和hashCode方法时为true,反之没有时为false
System.out.println(list.contains(p4));
System.out.println(list);
System.out.println("------------------是否还能够将重复的对象添加成功?-------------------");
list.add(new Person(30, "小强"));
System.out.println(list);
}
}
/*
* 菜品类. 名字 ,价格, id. corsh 顶配的类.
*/
public class Cai {
private String name; // 菜名
private double price ;//价格
private String id ; // 菜id . 001
public Cai() {
super();
}
public Cai(String name, double price, String id) {
super();
this.name = name;
this.price = price;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return id + "--[" + name +":"+ price+"]" ;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
long temp;
temp = Double.doubleToLongBits(price);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Cai other = (Cai) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Double.doubleToLongBits(price) != Double.doubleToLongBits(other.price))
return false;
return true;
}
}
/*
* 点菜程序.
* 1. 创建一个集合,保存所有的菜品.
* 2. 录入菜品的编号, 遍历集合,选择菜品 ,保存到新的集合.
* 3. exit . 不点了, 遍历 新的集合,即是你点过菜.
*
* =====================
* 根据价格去选择!
* 16块钱.
* 18块钱.
*
* ========================
*
* 带肉的 . 简单实现 . 菜名有肉就行. 菇
* 复杂实现 . 根据 菜的原料 ,去判断.
*
* 实现:
*
* 1. 定义类 : 菜品类. 名字 ,价格, id.
* 2. 创建菜品对象,保存到集合.
* a. 通过 id ,点菜 .
* b. 价格 选菜 .
* c. 菜名字 ,选菜.
*
* 3.选择的菜品 ,添加到点菜的集合中.
* 4. 遍历集合.
*/
public class Test {
public static void main(String[] args) {
Cai cai = new Cai("锅包肉", 28.8, "001");
System.out.println(cai);
}
}
步骤一:创建LinkedList集合,里面存储的元素的数据类型是Integer
步骤二:将1,2,3,4,5依次添加到集合中
步骤三:调用集合的push方法将6,7,8,9,10依次添加到集合中
步骤四:最后打印集合的效果为:[10, 9, 8, 7, 6, 1, 2, 3, 4, 5]
package day08_Test拓展三道编程题;
import java.util.LinkedList;
/*
* LinkedList的弹栈和压站
* push
* add
*/
public class Test001 {
public static void main(String[] args) {
//创建LinkedList集合,里面存储的元素的数据类型是Integer
LinkedList<Integer> stack = new LinkedList<Integer>();
//将1,2,3,4,5添加到集合中
stack.add(1);
stack.add(2);
stack.add(3);
stack.add(4);
stack.add(5);
System.out.println(stack);
System.out.println("------------------------------");
//调用集合的push方法将6,7,8,9,10添加到集合中
stack.push(6);
stack.push(7);
stack.push(8);
stack.push(9);
stack.push(10);
//最后打印集合的效果为:[10, 9, 8, 7, 6, 1, 2, 3, 4, 5]
System.out.println(stack);
}
}
1.定义一个员工类(Employee),要求具有以下属性:
a)empName(姓名)
b)sex(性别)
c)age(年龄)
2.定义一个List集合,存储以下”Employee”信息:
a)孙红雷 男 20
b)葛优 男 30
c)黄渤 男 25
d)孙俪 女 18
3.要求:
a)在”葛优”前面添加一个学员:王骏迪 女 17
b)定义一个Set集合存储Employee信息,要求不能存储相同的:姓名,性别,年龄的员工信息.并测试;
Employee类:
package day08_Test拓展三道编程题;
public class Employee {
private String name;
private char sex;
private int age;
public Employee(String name, char sex, int age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
}
public Employee() {
super();
// TODO Auto-generated constructor stub
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Employee [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + sex;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (sex != other.sex)
return false;
return true;
}
}
测试类:
package day08_Test拓展三道编程题;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Test002 {
public static void main(String[] args) {
List<Employee> empList = new ArrayList<>();
empList.add(new Employee("孙红雷",'男',20));
empList.add(new Employee("葛优",'男',30));
empList.add(new Employee("孙俪",'女',18));
//在”葛优”前面添加一个学员:王骏迪 女 17
empList.add(1,new Employee("王骏迪",'女',17));
//使用Set存储
Set<Employee> empSet = new HashSet<>();
empSet.add(new Employee("孙红雷",'男',20));
empSet.add(new Employee("葛优",'男',30));
empSet.add(new Employee("葛优",'男',30));//存储相同元素--失败
System.out.println(empSet);
}
}
1.定义一个存储数字的集合,并随意存储一些数据(要求这些数据中包含一些重复数字);
2.使用一种很方便的方式将这个集合中重复的数字去掉.
package day08_Test拓展三道编程题;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Test003 {
/*
* 1.定义一个存储数字的集合,并随意存储一些数据(要求这些数据中包含一些重复数字);
2.使用一种很方便的方式将这个集合中重复的数字去掉.
*/
public static void main(String[] args) {
List<Integer> intList = new ArrayList<>();
intList.add(10);
intList.add(20);
intList.add(20);
intList.add(30);
intList.add(30);
Set<Integer> intSet = new HashSet<>();
intSet.addAll(intList);
System.out.println(intSet);
}
}