需求:使用LinkedList存储一副扑克牌,然后实现洗牌功能
package cn.itcast.list; import java.util.LinkedList; import java.util.Random; /* * * 需求:使用LinkedList存储一副扑克牌,然后实现洗牌功能 * */ public class Demo1 { public static void main(String[] args) { // TODO Auto-generated method stub LinkedList pokers=createPoker(); /*System.out.println(pokers); System.out.println("牌数:"+pokers.size());*/ shufflePoker(pokers); showPoker(pokers); } //生成扑克牌的方法 public static LinkedList createPoker(){ //该集合用于存储扑克对象 LinkedList list=new LinkedList(); //定义数组存储所有的花色与点数 String[] colors= {"黑桃","红桃","梅花","方块"}; String[] nums= {"A","2","3","4","5","6","7","8","9","10","J","Q","K"}; for (int i=0;i<nums.length;i++) { for (int j=0;j<colors.length;j++) { list.add(new Poker(colors[j],nums[i])); } } return list; } //显示扑克牌 public static void showPoker(LinkedList pokers) { for (int i=0;i<pokers.size();i++) { System.out.print(pokers.get(i)); //换行 if (i%10==9) { System.out.println(); } } } //洗牌的功能 public static void shufflePoker(LinkedList pokers) { //创建随机数对象 Random random=new Random(); for (int i=0;i<100;i++) { //随机产生两个索引值 int index1=random.nextInt(pokers.size()); int index2=random.nextInt(pokers.size()); //根据索引值取出两张牌,然后交换两张牌的顺序 Poker poker1=(Poker) pokers.get(index1); Poker poker2=(Poker) pokers.get(index2); pokers.set(index1, poker2); pokers.set(index2, poker1); } } } //扑克类 class Poker{ String color;//花色 String num;//点数 public Poker(String color, String num) { super(); this.color = color; this.num = num; } @Override public String toString() { // TODO Auto-generated method stub return "{"+color+num+"}"; } } 结果: {黑桃A}{红桃J}{黑桃6}{红桃6}{方块8}{黑桃10}{黑桃K}{红桃A}{梅花9}{梅花J} {红桃4}{方块K}{方块Q}{方块9}{方块2}{黑桃Q}{黑桃3}{红桃3}{红桃5}{梅花A} {梅花Q}{梅花3}{黑桃5}{方块J}{红桃10}{梅花K}{梅花6}{方块7}{方块6}{黑桃9} {梅花8}{黑桃8}{红桃2}{方块A}{梅花4}{梅花7}{黑桃2}{红桃7}{梅花5}{黑桃J} {红桃8}{红桃Q}{黑桃4}{方块5}{方块4}{红桃9}{方块10}{方块3}{梅花10}{黑桃7} {梅花2}{红桃K}
编写一个函数根据人的年龄进行存储
package cn.itcast.list; import java.util.LinkedList; public class Demo2 { public static void main(String[] args) { // TODO Auto-generated method stub LinkedList list=new LinkedList(); list.add(new Person("狗娃", 7)); list.add(new Person("狗剩", 17)); list.add(new Person("铁蛋", 3)); list.add(new Person("美美", 30)); //编写一个函数根据人的年龄进行存储 for (int i=0;i<list.size()-1;i++) { for (int j=i+1;j<list.size();j++) { //符合条件交换位置 Person p1=(Person) list.get(i); Person p2=(Person) list.get(j); if (p1.age>p2.age) { //交换位置 list.set(i, p2); list.set(j, p1); } } } System.out.println(list); } } class Person{ String name; int age; public Person(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { // TODO Auto-generated method stub return "{名字:"+this.name+" 年龄:"+this.age+"}"; } } 结果: [{名字:铁蛋 年龄:3}, {名字:狗娃 年龄:7}, {名字:狗剩 年龄:17}, {名字:美美 年龄:30}]
Vector 底层也是维护了一个Object的数组实现的,实现与ArrayList是一样的,但是Vector是线程安全的,操作效率低
Vector与ArrayList 的区别:
相同点: 底层都使用了Object数组实现的
不同点:
- ArrayList是线程不同步的,操作效率高;Vector是线程同步的,操作效率低
- ArrayList是JDK1.2出现的,Vector是JDK1.0的时候出现的
package cn.itcast.list; import java.util.Enumeration; import java.util.Vector; public class Demo3 { public static void main(String[] args) { // TODO Auto-generated method stub Vector v=new Vector(); //添加元素 v.addElement("张三"); v.addElement("李四"); v.addElement("王五"); //迭代该集合 Enumeration e= v.elements();//获取迭代器 while (e.hasMoreElements()) { System.out.println(e.nextElement()); } } } 结果: 张三 李四 王五
Set:无序,不可重复
无序:添加元素的顺序与元素出来的顺序是不一致的
import java.util.HashSet; import java.util.Set; public class Demo1 { public static void main(String[] args) { // TODO Auto-generated method stub Set set=new HashSet(); set.add("张三"); set.add("李四"); set.add("王五"); System.out.println("添加成功吗?"+" :"+set.add("李四")); System.out.println(set); } } 结果: 添加成功吗? :false [李四, 张三, 王五]
HashSet:底层是使用了哈希表来支持的,特点:存取速度快
HashSet的实现原理:
往HashSet添加yu元素的时候,HashSet会先调用元素的hashCode方法得到元素的哈希值,然后通过元素的哈希值经过移位等运算,就可以算出该元素在哈希表中的存储位置。
情况1:如果算出元素存储的位置目前没有任何y元素存储,那么该元素可以直接存储到该位置上。
情况2:如果算出该元素的存储位置目前已经存在有其他的元素了,那么会调用该元素的equals方法与该位置的元素再比较一次,如果equals返回的是true,那么该元素与这个位置上的元素就视为重复元素,不允许添加,如果equals方法返回的是false,那么该元素运行添加。
哈希表的其中一个特点:桶式结构
package cn.istcast.set; import java.util.HashSet; public class Demo2 { public static void main(String[] args) { // TODO Auto-generated method stub HashSet set=new HashSet(); set.add(new Person(110,"狗娃")); set.add(new Person(220,"狗剩")); set.add(new Person(330,"铁蛋")); //在现实生活中,只要编号一致就为同一个人 System.out.println("添加成功吗?"+set.add(new Person(110,"陈大福"))); System.out.println("集合的元素:"+set); } } class Person{ int id; String name; public Person(int id, String name) { super(); this.id = id; this.name = name; } @Override public String toString() { // TODO Auto-generated method stub return "{编号:"+this.id+" 姓名:"+this.name+"}"; } @Override public int hashCode() { // TODO Auto-generated method stub //System.out.println("--hashCode调用了--"); System.out.println("----hashCode----"); return this.id; } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub System.out.println("----equals----"); Person p=(Person)obj; return this.id==p.id; } } 结果: ----hashCode---- ----hashCode---- ----hashCode---- ----hashCode---- ----equals---- 添加成功吗?false 集合的元素:[{编号:330 姓名:铁蛋}, {编号:220 姓名:狗剩}, {编号:110 姓名:狗娃}]
重写hashCode
package cn.istcast.set; public class Demo4 { public static void main(String[] args) { // TODO Auto-generated method stub String str1="hello"; String str2=new String("hello"); System.out.println("两个是同一个对象吗?"+(str1==str2)); System.out.println("str1的hashCode:"+str1.hashCode()); System.out.println("str2的hashCode:"+str2.hashCode()); /*hashCode方法默认情况下表示的是内存地址,String类已经重写了Object的hashCode方法了 * * 注意:如果两个字符串的内容一致,那么返回的hashCode码肯定也会一致的。 * */ } } 结果: 两个是同一个对象吗?false str1的hashCode:99162322 str2的hashCode:99162322
需求:接受键盘录入用户名与密码,如果用户名与密码已经存在集合中,那么就是视为重复元素,不允许添加到HashSet中
package cn.istcast.set; import java.util.HashSet; import java.util.Scanner; /* * 需求:接受键盘录入用户名与密码,如果用户名与密码已经存在集合中,那么就是视为重复元素,不允许添加到HashSet中 * * */ public class Demo3 { public static void main(String[] args) { // TODO Auto-generated method stub Scanner sc=new Scanner(System.in); HashSet set=new HashSet(); while (true) { System.out.println("请输入用户名:"); String userName=sc.next(); System.out.println("请输入密码:"); String password=sc.next(); //创建一个对象 User user=new User(userName, password); if (set.add(user)) { System.out.println("注册成功..."); System.out.println("当前的用户有:"+set); } else { System.out.println("注册失败..."); } } } } class User{ String userName; String password; public User(String userName, String password) { super(); this.userName = userName; this.password = password; } @Override public String toString() { // TODO Auto-generated method stub return "{ 用户名:"+this.userName+" 密码:"+this.password; } @Override public int hashCode() { // TODO Auto-generated method stub return userName.hashCode()+password.hashCode(); } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub User user=(User)obj; return this.userName.equals(user.userName)&&this.password.equals(user.password); } } 结果: 请输入用户名: 123 请输入密码: abc 注册成功... 当前的用户有:[{ 用户名:123 密码:abc] 请输入用户名: 123 请输入密码: abc 注册失败... 请输入用户名: abc 请输入密码: 123 注册成功... 当前的用户有:[{ 用户名:123 密码:abc, { 用户名:abc 密码:123] 请输入用户名:
TreeSet:如果元素具备自然顺序的特性,那么就按照元素自然顺序d的特性j进行排序存储
import java.util.TreeSet; public class Demo5 { public static void main(String[] args) { // TODO Auto-generated method stub TreeSet tree=new TreeSet(); /*tree.add(1); tree.add(10); tree.add(7); tree.add(19); tree.add(9);*/ tree.add('b'); tree.add('c'); tree.add('a'); tree.add('f'); System.out.println(tree); } } 结果: [a, b, c, f]
TreeSet添加自定义元素:
TreeSet要注意的事项:
- 往TreeSet添加元素的时候,如果元素本身具备了自然顺序的特性,那么就按照元素自然顺序的特性进行排序存储
- 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,那么该元素所属的类必须要实现Comparable接口,把元素的比较规则定义在compare(T o)方法上
- 往TreeSet添加元素的时候,如果比较元素的时候,compareTo方法返回的是0,那么该元素就被视为重复元素,不允许添加(注意:TreeSet与HashCode,equals方法是没有任何关系的)
- 往TreeSet添加元素的时候,如果元素本身没有具备自然顺序的特性,而元素所属的类也没有实现Comparable接口,那么必须要在创建一个TreeSet的时候传入一个比较器
- 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,而元素所属的类已经实现了Comparable接口,而创建TreeSet对象的时候,也传入了比较器,那么是比较器的比较规则优先使用
package cn.istcast.set; import java.util.TreeSet; /* TreeSet添加自定义元素: TreeSet要注意的事项: 1.往TreeSet添加元素的时候,如果元素本身具备了自然顺序的特性,那么就按照元素自然顺序的特性进行排序存储 2.往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,那么该元素所属的类必须要实现Comparable接口,把元素的比较规则定义在compare(T o)方法上 */ public class Demo6 { public static void main(String[] args) { // TODO Auto-generated method stub TreeSet tree=new TreeSet(); tree.add(new Emp(113, "捞比", 300)); tree.add(new Emp(110, "捞货", 100)); tree.add(new Emp(220, "老宫", 200)); tree.add(new Emp(120, "大头", 500)); System.out.println("集合的元素:"+tree); } } class Emp implements Comparable{ int id; String name; int salary; public Emp(int id, String name, int salary) { super(); this.id = id; this.name = name; this.salary = salary; } @Override public String toString() { // TODO Auto-generated method stub return "{ 编号"+this.id+" 姓名:"+this.name+" 薪水:"+this.salary+"}"; } @Override//元素与元素之间的比较规则 //负整数,零或正整数,根据此对象是小于,等于还是大于指定对象 public int compareTo(Object o) { // TODO Auto-generated method stub Emp e=(Emp)o; return this.salary-e.salary; } } 结果: 集合的元素:[{ 编号110 姓名:捞货 薪水:100}, { 编号220 姓名:老宫 薪水:200}, { 编号113 姓名:捞比 薪水:300}, { 编号120 姓名:大头 薪水:500}]
TreeSet的存储原理:底层是使用了二叉树数据结构实现
package cn.istcast.set; import java.util.Comparator; import java.util.TreeSet; /* TreeSet添加自定义元素: TreeSet要注意的事项: 1.往TreeSet添加元素的时候,如果元素本身具备了自然顺序的特性,那么就按照元素自然顺序的特性进行排序存储 2.往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,那么该元素所属的类必须要实现Comparable接口,把元素的比较规则定义在compare(T o)方法上 3.往TreeSet添加元素的时候,如果比较元素的时候,compareTo方法返回的是0,那么该元素就被视为重复元素,不允许添加(注意:TreeSet与HashCode,equals方法是没有任何关系的) 4.往TreeSet添加元素的时候,如果元素本身没有具备自然顺序的特性,而元素所属的类也没有实现Comparable接口,那么必须要在创建一个TreeSet的时候传入一个比较器 如何自定义比较器:自定义一个类实现Comparator接口即可,把元素与元素之间的比较规则定义在compare方法内即可。 自定义比较器的格式: class 类名 implements Comparator{ } */ public class Demo6 { public static void main(String[] args) { // TODO Auto-generated method stub //创建一个比较器对象 MyComparator my=new MyComparator(); //创建TreeSetd的时候传入比较器 TreeSet tree=new TreeSet(my); tree.add(new Emp(113, "捞比", 300)); tree.add(new Emp(110, "捞货", 100)); tree.add(new Emp(220, "老宫", 200)); tree.add(new Emp(120, "大头", 500)); System.out.println("集合的元素:"+tree); } } class Emp {//implements Comparable{ int id; String name; int salary; public Emp(int id, String name, int salary) { super(); this.id = id; this.name = name; this.salary = salary; } @Override public String toString() { // TODO Auto-generated method stub return "{ 编号"+this.id+" 姓名:"+this.name+" 薪水:"+this.salary+"}"; } //@Override//元素与元素之间的比较规则 //负整数,零或正整数,根据此对象是小于,等于还是大于指定对象 /*public int compareTo(Object o) { // TODO Auto-generated method stub Emp e=(Emp)o; System.out.println(this.name+"compare"+e.name); return this.salary-e.salary; }*/ } class MyComparator implements Comparator{ @Override public int compare(Object o1, Object o2) { // TODO Auto-generated method stub Emp e1=(Emp)o1; Emp e2=(Emp)o2; return e1.id-e2.id; } } 结果: 集合的元素:[{ 编号110 姓名:捞货 薪水:100}, { 编号113 姓名:捞比 薪水:300}, { 编号120 姓名:大头 薪水:500}, { 编号220 姓名:老宫 薪水:200}]
推荐使用:使用比较器(Comparator)
TreeSet是可以对字符串j进行排序的,因为字符串已经实现了Comparable接口。
字符串的比较规则:
情况一:对应位置有不同的字符出现,比较的就是对应位置上不同的字符
情况二:对应位置上的字符都一样,比较的就是字符串的长度
package cn.istcast.set; import java.util.TreeSet; public class Demo7 { public static void main(String[] args) { // TODO Auto-generated method stub TreeSet tree=new TreeSet(); tree.add("abcccccc"); tree.add("abc"); System.out.println(tree); } } 结果: [abc, abcccccc]
package cn.istcast.set; import java.util.TreeSet; public class Demo7 { public static void main(String[] args) { // TODO Auto-generated method stub TreeSet tree=new TreeSet(); tree.add("abcccccc"); tree.add("abw"); System.out.println(tree); } } 结果: [abcccccc, abw]
public class Demo7 { public static void main(String[] args) { // TODO Auto-generated method stub TreeSet tree=new TreeSet(); tree.add("abcccccc"); tree.add("abw"); System.out.println(tree); System.out.println("abc".compareTo("abccccc")); System.out.println("abw".compareTo("abcccccc")); } } 结果: [abcccccc, abw] -4 20
泛型:泛型是jdk1.5使用的新特性
泛型的好处:
- 将运行时的异常提前至了编译时
- 避免了无谓的强制类型转换
泛型在集合中的常见应用:
注意:泛型没有多态的概念,左右两边的数据类型必须要一致,或者是只写一边的泛型类型。
推荐使用:两边都写泛型
package cn.itcast.genrictiry; import java.util.ArrayList; /* 泛型: 需求:把一个集合中元素全部转成大写 */ public class Demo1 { public static void main(String[] args) { // TODO Auto-generated method stub ArrayList<String> list=new ArrayList<String>();//<String>表示该容器只能存储字符串类型的数据 list.add("aa"); list.add("bb"); list.add("cc"); for (int i=0;i<list.size();i++) { String str=list.get(i); System.out.println("大写:"+str.toUpperCase()); } } } 结果: 大写:AA 大写:BB 大写:CC
自定义泛型:自定义泛型就是一个数据类型的占位符或者是一个数据类型的变量。
方法上自定义泛型:
修饰符 <声明自定义的泛型>返回值类型 函数名(使用自定义泛型...){
}
在泛型中不能使用基本数据类型,如果需要使用基本数据类型,那么就使用基本数据类型对应的包装类型
byte------>Byte
short----->Short
int------->Integer
long------>Long
double---->Double
float----->Float
boolean--->Boolean
char------>Character
方法泛型注意的事项:
1.在方法上自定义泛型,这个自定义泛型的具体数据类型是在调用该方法的时候传入实参时确定的
2.自定义泛型只要符合标识符的命名规则即可,但是自定义泛型一般我们都习惯使用一个大写字母表示
T Type 类型
E Element 元素
泛型类:
泛型类:
泛型类的定义格式:
class 类名<声明自定义泛型>{
}
泛型类要注意的事项:
1.在类上自定义泛型的具体数据类型是在使用该类的时候创建对象确定的
2.如果一个类在类上已经声明了自定义泛型,如果使用该类创建对象的时候没有指定泛型的具体数据类型,那么默认为Object类型
3.在类上自定义泛型不能作用于静态的方法,如果静态的方法需要使用自定义泛型,那么需要在方法上自己声明使用(类上的泛型的具体的数据类型是在创建对象的时候才知道的,但是静态的方法不需要创建变量)
public class Demo3 { public static void main(String[] args) { // TODO Auto-generated method stub Integer[] arr= {10,12,14,19}; //创建了数组的工具类对象 /*MyArrays arrTool=new MyArrays(); arrTool.reverse(arr); System.out.println(arrTool.toStirng(arr));*/ MyArrays<Integer> tool=new MyArrays<Integer>(); tool.reverse(arr); System.out.println("数组的元素:"+tool.toStirng(arr)); MyArrays<String> tool2=new MyArrays<String>(); String[] arr2= {"aaa","bbb","ccc"}; tool2.reverse(arr2); } } class MyArrays<T>{ //元素反转 public void reverse(T[] arr) { for (int startIndex=0,endIndex=arr.length-1;startIndex<endIndex;startIndex++,endIndex--) { T temp=arr[startIndex]; arr[startIndex]=arr[endIndex]; arr[endIndex]=temp; } } public String toStirng(T[] arr) { StringBuilder sb=new StringBuilder(); for (int i=0;i<arr.length;i++) { if(i==0) { sb.append("["+arr[i]+","); } else if (i==arr.length-1) { sb.append(arr[i]+"]"); } else { sb.append(arr[i]+","); } } return sb.toString(); } } 结果; 数组的元素:[19,14,12,10]
泛型接口:
泛型接口的定义格式:
interface 接口名<声明自定义泛型>{
}
泛型接口要注意的事项:
1.接口上自定义的泛型的具体数据类型是在实现一个接口的时候指定的
2.在接口上自定义的泛型如果在实现接口的时候没有指定具体的数据类型,那么默认为Object类型
需求:目前我实现一个接口的时候,我还不明确我目前要操作的数据类型,我要等待创建接口实现类对象的时候我们才能指定泛型的数据类型
如果要延迟j接口自定义泛型d的具体数据类型,那么格式如下:
格式:
public class Demo4<T> implements Dao<T>
public class Demo4<T> implements Dao<T>{ public static void main(String[] args) { // TODO Auto-generated method stub Demo4<String> demo=new Demo4<String>(); } @Override public void add(T t) { // TODO Auto-generated method stub } } interface Dao<T>{ public void add(T t); } 结果:
泛型的上下限:
需求1:定义一个函数可以接收任意类型的集合对象,要求接收的集合对象只能存储Integer或者是Integer的父类类型数据
需求2:定义一个函数可以接收任意类型的集合对象,要求接收的集合对象只能存储Number或者是Number的子类类型数据
泛型中的通配符:?
? super Integer: 只能存储Integer或者是Integer父类元素 泛型的下限
? extends Number: 只能存储Number或者是Number类型的子类数据 泛型的上限
package cn.itcast.genrictiry; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; /* 泛型的上下限: 需求1:定义一个函数可以接收任意类型的集合对象,要求接收的集合对象只能存储Integer或者是Integer的父类类型数据 需求2:定义一个函数可以接收任意类型的集合对象,要求接收的集合对象只能存储Number或者是Number的子类类型数据 泛型中的通配符:? ? super Integer:只能存储Integer或者是Integer父类元素 泛型的下限 ? extends Number: 只能存储Number或者是Number类型的子类数据 泛型的上限 */ public class Deno5 { public static void main(String[] args) { // TODO Auto-generated method stub ArrayList<Integer> list1=new ArrayList<Integer>(); ArrayList<Number> list2=new ArrayList<Number>(); HashSet<String> set=new HashSet<String>(); print(list1); getData(list1); } //泛型的上限 public static void getData(Collection<? extends Number> c) { } //泛型的下限 public static void print(Collection<? super Integer> c) { } } 结果: