泛型
通过<数据类型>接收一种数据类型,在编译的时候会使用这种类型检测集合中的元素,如果不是<>中规定的类型,就不允许添加到集合当中(编译不通过).
作用:
- 使用了泛型不再需要进行强制类型转换,容错处理,向下转型.------简化代码
- 将运行阶段的问题提前到了编译阶段检查,提高了代码的安全性和编程的效率.
- 泛型的擦除:泛型只是在编辑阶段检查元素的类型,一到运行阶段泛型就消失了.
- 泛型的使用场景:
- 类上
- 接口上
- 方法上
public static void main(String[] args) {
//当list指定了具体的String泛型之后,里面的元素只能是String
ArrayList<String> list = new ArrayList<>();
list.add("java1");
list.add("java2");
list.add("java5");
list.add("java7");
//list.add(3);
System.out.println(list);
//获取迭代器
//当集合的泛型确定之后,让迭代器的泛型与之一致即可
Iterator<String> iterator = list.iterator();
//使用泛型前
//遍历
// while (iterator.hasNext()) {
// Object object = (Object) iterator.next();
// //容错处理
// if (!(object instanceof String)) {
// throw new ClassCastException("数据转化异常");
// }
// //向下转型
// String string = (String)object;
//
// System.out.println(string.length());
// }
//使用泛型后
while (iterator.hasNext()) {
String string = (String) iterator.next();
System.out.println(string.length());
}
}
泛型在类上的使用
public class Demo3 {
public static void main(String[] args) {
Student student = new Student();
Computer computer = new Computer("苹果");
Phone phone = new Phone("苹果");
//将工具交给学生
student.setObj(computer);//多态
//使用泛型前
//获取工具
// Object object = student.getObj();//多态
//
// //向下转型
// Computer computer2 = (Computer)object;//computer2 = object = new Computer("苹果")
// Phone phone2 = (Phone)object;//phone2 = object = new Computer("苹果") 错误
//使用泛型后
//这里通过使用泛型:保证了Student1类的使用灵活性而且可以简化代码,提高代码的效率
Student1<Computer> student1 = new Student1<>();
student1.setObj(computer);
Computer computer3 = student1.getObj();
}
}
//使用泛型前
class Student{
private Object obj;
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
}
//使用泛型后
/*
* E代表任意一种数据类型,但是<>中不一定是E,可以是任意字符.
* 在类的后面加<>就是在给类使用泛型.
* 在类上确定的泛型可以在成员上直接使用
*/
class Student1<E>{
private E obj;
public E getObj() {
return obj;
}
public void setObj(E obj) {
this.obj = obj;
}
}
class Tool{
String name;
public Tool() {
}
public Tool(String name) {
this.name = name;
}
}
class Phone extends Tool{
public Phone(String name) {
super(name);
}
}
class Computer extends Tool{
public Computer(String name) {
super(name);
}
}
泛型在方法上的使用
- 方法上的泛型与类上的泛型一致
- 方法上独立使用泛型
- 注意:泛型在使用之前一定要先进行声明
- 声明的方式:在方法的最前面加<符号>
- 作用:让方法内与方法的泛型保持一致
- 静态方法上使用泛型
- 静态方法上无法使用类上的泛型,类上的泛型必须通过创建对象才能使用.
- 静态方法的调用不需要对象,所以静态方法如果想使用泛型,必须自己单独使用.
import java.util.ArrayList;
public class Demo4 {
public static void main(String[] args) {
Teacher<String> teacher = new Teacher<>();
//1.方法上的泛型与类上的泛型一致
teacher.play("haha");
//2.方法上独立使用泛型
teacher.show(2);
//3.静态方法上使用泛型
Teacher.run(5);
}
}
class Teacher<E>{
//1.方法上的泛型与类上的泛型一致
public E play(E e){
return e;
}
//2.方法上独立使用泛型
/*
* 注意:泛型在使用之前一定要先进行声明
* 声明的方式:在方法的最前面加<符号>
* 作用:让方法内与方法的泛型保持一致
*/
public <F> void show(F f){
ArrayList<F> list = null;
}
//3.静态方法上使用泛型
/*
* 静态方法上无法使用类上的泛型,类上的泛型必须通过创建对象才能使用.
* 静态方法的调用不需要对象,所以静态方法如果想使用泛型,必须自己单独使用.
*/
public static<W> void run(W w){
}
}
接口上使用泛型
子类使用泛型的情况
第一种:接口有泛型,子类没有遵守对应的泛型
注意:必须给接口指定一个具体的泛型类型
第二种:接口有泛型,子类与接口一致,遵守了对应的泛型
类上的泛型确定了,接口上的泛型就确定了,重写方法上的泛型也就确定了
public class Demo5 {
public static void main(String[] args) {
Dog dog = new Dog();
dog.play("haha");
Cat<String> cat = new Cat<>();
}
}
//接口上使用泛型
interface Inter<E>{
public void play(E e);
}
//子类使用泛型的情况
/*
* 第一种:接口有泛型,子类没有遵守对应的泛型
* 注意:必须给接口指定一个具体的泛型类型
*/
class Dog implements Inter<String>{
//重写的方法的泛型与接口一致
public void play(String e) {
// TODO Auto-generated method stub
}
//自定义的方法可以使用接口的泛型,也可以自定义泛型.
public <F> void show(F f) {
}
}
/*
* 第二种:接口有泛型,子类与接口一致,遵守了对应的泛型
* 类上的泛型确定了,接口上的泛型就确定了,重写方法上的泛型也就确定了
*/
class Cat<E> implements Inter<E>{
public void play(E e) {
// TODO Auto-generated method stub
}
}
? : 通配符,表示一种或几种数据类型
-
限制上限:<? extends E>:限制的是整个<>中可以取的泛型类型是E类及E类的子类
-
限制下限:<? super E>:限制的是整个<>中可以取的泛型类型是E类及E类的父类
-
注意点:在取类型的时候,类型之间一定有继承关系.
import java.util.ArrayList;
import java.util.Collection;
/*
* 这里讲的是限制上限:<? extends E>
*/
public class Demo6 {
public static void main(String[] args) {
//
ArrayList<Student2> list1 = new ArrayList<>();
list1.add(new Student2("bingbing", 1));
//可以传参:因为Student2是Person1的子类,可以实现遍历
bianli(list1);
ArrayList<Teacher8> list2 = new ArrayList<>();
list2.add(new Teacher8("bingbing", 1));
//可以传参:因为Teacher1是Person1的子类,可以实现遍历
bianli(list2);
ArrayList<Person1> list3 = new ArrayList<>();
list3.add(new Person1("bingbing", 1));
//可以传参
bianli(list3);
ArrayList<Object> list4 = new ArrayList<>();
list4.add(new Object());
//可以传参:因为Object是Person1的父类,不可以实现遍历
//bianli(list4);
}
public static void bianli(Collection<? extends Person1> e){
System.out.println("遍历了");
}
}
class Person1{
String name;
int age;
public Person1() {
super();
// TODO Auto-generated constructor stub
}
public Person1(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person1 [name=" + name + ", age=" + age + "]";
}
}
class Teacher8 extends Person1{
public Teacher8(String name, int age) {
super(name, age);
}
}
class Student2 extends Person1{
public Student2(String name, int age) {
super(name, age);
}
}
import java.util.Comparator;
import java.util.TreeSet;
public class Demo7 {
public static void main(String[] args) {
//限制下限 <? super E>
//TreeSet(Comparator<? super E> comparator) :这里的E跟TreeSet后面的泛型类型一致,所以现在E应该表示的Student3
//创建Student3类的比较器对象
ComWithStu comWithStu = new ComWithStu();
//创建Teacher1类的比较器对象
ComWithTea comWithTea = new ComWithTea();
//创建Person1类的比较器对象
ComWithPerson comWithPerson = new ComWithPerson();
//创建GoodStudent类的比较器对象
ComWithGood comWithGood = new ComWithGood();
TreeSet<Student3> set = new TreeSet<>(comWithStu);//因为这里限制的是Student3及他的父类
//TreeSet<Student3> set = new TreeSet<>(comWithTea);//不可以使用,因为Teacher2类与Student3类没有关系
//TreeSet<Student3> set = new TreeSet<>(comWithPerson);//可以 ,因为Person2类是Student3类的父类
//TreeSet<Student3> set = new TreeSet<>(comWithGood);//不可以,因为GoodStudent类是Student3类的子类
set.add(new Student3("bingbing"));
set.add(new Student3("bingbing1"));
set.add(new Student3("bingbing2"));
}
}
//创建Student3类的比较器
class ComWithStu implements Comparator<Student3>{
public int compare(Student3 o1, Student3 o2) {
return o1.name.compareTo(o2.name);
}
}
//创建Teacher2类的比较器
class ComWithTea implements Comparator<Teacher2>{
public int compare(Teacher2 o1, Teacher2 o2) {
return 0;
}
}
//创建Person2类的比较器
class ComWithPerson implements Comparator<Person2>{
public int compare(Person2 o1, Person2 o2) {
return 0;
}
}
//创建GoodStudent类的比较器
class ComWithGood implements Comparator<GoodStudent>{
public int compare(GoodStudent o1, GoodStudent o2) {
return 0;
}
}
class Person2{
String name;
public Person2(String name) {
super();
this.name = name;
}
public String toString() {
return "Person2 [name=" + name + "]";
}
}
class Teacher2 extends Person2{
public Teacher2(String name) {
super(name);
}
}
class Student3 extends Person2{
public Student3(String name) {
super(name);
}
}
class GoodStudent extends Student3{
public GoodStudent(String name) {
super(name);
}
}
Map:
-
比较Map和Collection
- Collection:是集合,是接口,是直接存值
- Map:是集合,是接口,存储的是键值对.一个元素就是一个键(key)值(value)对.键必须是唯一的,值可以相同.
-
Map需要设置两个泛型,一个是key的,一个是value的.
-
设置key是,最好使用一个常量作为key,比如String,因为他本事是固定不变的,从map的底层实现来看,进行存取的效率会更高.
Map接口的方法
- 增加
- V put(K key,V value) 增加一个键值对
- void putAll(Map<? extends K,? extends V> map) 增加多个
- 删除
- V remove(Object key) 根据key删除元素
- void clear() 删除全部
- 获取
- V get(Object key) 根据key查找元素
- int size() 获取键值对的个数
- Set keySet() 遍历方法一
- Set<Map.Entry<K,V>> entrySet() 遍历方法二
- 常用的判断
- boolean isEmpty()
- boolean containsKey(K key) 是否包含当前的key
- boolean containsValue(V value) 是否包含当前的value
public class Demo8 {
public static void main(String[] args) {
/*
* Map需要设置两个泛型,一个是key的,一个是value的.
* 设置key是,最好使用一个常量作为key,比如String,因为他本事是固定不变的,从map的底层实现来看,进行存取的效率会更高.
*/
Map<String, String> map = new HashMap<String, String>();
//介绍Map接口的方法
//1.增加
//V put(K key,V value) 增加一个键值对
map.put("01", "java");
map.put("02", "html");
map.put("03", "python");
map.put("04", "BigData");
/*
* 由于map中的key是唯一的,所以当给同一个key赋两次值,后面的值会将前面的值覆盖.
* 对于返回值:如果当前的key之前没有对应值,返回null.如果已经有值了,会将原来被替换的值返回.
*/
System.out.println(map.put("01", "iOS"));
System.out.println(map);
//void putAll(Map<? extends K,? extends V> map) 增加多个
//2.删除
//V remove(Object key) 根据key删除元素
// System.out.println(map.remove("01"));
//void clear() 删除全部
// map.clear();
// System.out.println(map);
//3.获取
//V get(Object key) 根据key查找元素
System.out.println(map.get("04"));
//int size() 获取键值对的个数
System.out.println(map.size());
//Set<K> keySet() 遍历方法一
//Set<Map.Entry<K,V>> entrySet() 遍历方法二
//4.常用的判断
//boolean isEmpty()
System.out.println(map.isEmpty());//false
//boolean containsKey(K key) 是否包含当前的key
System.out.println(map.containsKey("01"));//true
//boolean containsValue(V value) 是否包含当前的value
System.out.println(map.containsValue("java"));//false
}
}
Set keySet() 遍历方法一
- 通过这个方法得到所有的key,存放在set中,利用set的迭代器遍历得到每一个key,再利用key得到值
Set<Map.Entry<K,V>> entrySet() 遍历方法二
- 通过这个方法得到所有的entry(键值对),存放在set中,利用set的迭代器遍历得到每一个entry,再调用entry的方法得到key和value
了解:
-
为什么要将Entry映射关系接口放入Map接口中?
Entry是Map内的一个静态接口.因为有了集合中的键值对才有映射关系.而当前的映射关系又是对集合内部的描述.所以…
public class Demo9 {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("01", "java");
map.put("02", "html");
map.put("03", "python");
map.put("04", "BigData");
System.out.println(map);
//Set<K> keySet() 遍历方法一
//得到set
Set<String> set1 = map.keySet();
//得到迭代器
Iterator<String> iterator1 = set1.iterator();
//遍历得到所有的key,通过key获取value
while (iterator1.hasNext()) {
String key = (String) iterator1.next();
System.out.println("key:"+key+" value:"+map.get(key));
}
//Set<Map.Entry<K,V>> entrySet() 遍历方法二
//得到set
Set<Map.Entry<String,String>> set2 = map.entrySet();
//得到迭代器
Iterator<Map.Entry<String,String>> iterator2 = set2.iterator();
//遍历
while (iterator2.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator2.next();
//注意:这里可以通过setValue对map的值进行更改,但是不建议在这里改.
//entry.setValue("ok");
System.out.println("key1:"+entry.getKey()+" value1:"+entry.getValue());
}
}
}
HashMap
对他的去重就是对key进行去重,方法与操作HashSet一致—通过给key重写hashCode和equals方法
TreeMap:对他的去重和排序就是对key进行去重和排序,与TreeSet一致
- 系统排序 让key实现Comparable接口,重写compareTo方法
- 人工排序 创建比较器类,实现Comparetor接口,重写compare方法.然后直接作用于TreeMap即可.
public class Lianxi1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
LinkedList linkedList1 = new LinkedList();
Line line = new Line();
while(true) {
System.out.println("请选择添加还是删除字符,添加按1.删除按2.退出按0 ");
String choose = scanner.next();
if (choose.equals("2")) {//判断用户选择的功能
if (linkedList1.size()==0) {//先判断集合此时有没有元素,如果没有要先添加元素
System.out.println("现在集合为空,请先添加字符");
continue;
}else {
linkedList1 = line.deleteCharater(linkedList1);//从集合的开头删除元素
}
}
if(choose.equals("1")) {//判断用户选择的功能
System.out.println("请输入要添加的字符");
String string = scanner.next();
linkedList1 = line.addCharater(linkedList1, string);//从集合的后方添加元素
}
if(choose.equals("0")) {//判断用户选择的功能
System.exit(0);
}
else if(!(choose.equals("1")||choose.equals("2"))) {//判断用户选择的功能,如果不是需要的数字,就提醒输入不正确
System.out.println("请输入正确的数字");
}
}
}
}
class Line{
public LinkedList addCharater(LinkedList linkedList, String string) {
linkedList.addLast(string);
System.out.println(linkedList);
return linkedList;
}
public LinkedList deleteCharater(LinkedList linkedList) {
linkedList.pollFirst();
System.out.println(linkedList);
return linkedList;
}
}
import java.util.TreeSet;
import java.util.Comparator;
public class Lianxi2 {
/*步骤:1.创建比较器类实现Comparetor接口,重写compare方法
2.创建比较器对象,并指定给存储元素的TreeSet*/
public static void main(String[] arrgs){
Person3 person =new Person3 ();
TreeSet set = new TreeSet<>(person);//2.将Person3的对象存入TreeSet,按照年龄和比较
set.add(new Person3("bingbing",16));
set.add(new Person3("bingbing",16));
set.add(new Person3("bingbing1",15));
set.add(new Person3("bingbing",15));
System.out.println(set);
}
}
TreeMap的注意点
-
什么类型的数据可以作为TreeMap的key?
答:实现了Comparable接口,或者使用了比较实现了Comparetor接口)的元素.常见的:String nteger,Double
不行的类型:ArrayList,数组 -
作为key的类型,与他的内部有没有关系?
答:可以.元素能不能充当key,与他内部无关.只看他有没有实现Comparable接口.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.TreeMap;
public class Demo2 {
public static void main(String[] args) {
//验证:ArrayList,数组不能充当Map的key,因为他们本身都没有实现Comparable接口
// TreeMap<ArrayList<Cat>, String> map = new TreeMap<>();
// map.put(new ArrayList<>(), "01");
// System.out.println(map);
// TreeMap<Cat[], String> map = new TreeMap<>();
// map.put(new Cat[]{new Cat(),new Cat()}, "01");
// System.out.println(map);
// *2.作为key的类型,与他的内部有没有关系?
//*答:可以.元素能不能充当key,与他内部无关.只看他有没有实现Comparable接口.
TreeMap<Cat, String> map = new TreeMap<>();
map.put(new Cat(), "01");
System.out.println(map);
}
}
class Cat implements Comparable<Cat>{
String name;
int age;
Object obj;
@Override
public int compareTo(Cat o) {
// TODO Auto-generated method stub
return 0;
}
}