Java基础Day16

day16

  1. 泛型
    1.1 泛型的概念和使用
    泛型: 广泛的类型.定义一个类,类中的方法的参数或者是返回值类型,不能确定,可以使用泛型来进行定义

举例: ArrayList中的add方法,可以存储任意的引用数据类型,因此方法的参数不确定,使用泛型表示
ArrayList arr = new ArrayList();
arr.add();

泛型的定义方式: 类比 ArrayList
<泛型的声明> : E----->Elements 元素,就表示广泛的类型
泛型的声明规范 : 可以使用一个符合规范的大写字母来进行表示
通常,使用E,T----Type,也可以使用W,Q,S…

泛型的使用: 创建类对象时,给出具体的泛型的类型
ArrayList arr1 = new ArrayList();

1.2 泛型的好处和使用注意事项
泛型的好处:

  1. 泛型提高代码的安全性,将运行时会发生的转型错误,提前到代码的编译环节. 带有泛型的集合,集合中能存储的数据类型就已经确定,保证集合中元素类型一致,不会发生转型的异常
  2. 泛型可以省略掉强制类型转换过程.存储数据时,已经确定数据类型,获取数据时,直接获取到指定类型

代码
package com.zgjy.fanxing;

import java.util.ArrayList;
import java.util.Iterator;

public class FanXingDemo1 {

public static void main(String[] args) {
	
	//getArr();
	getFanXingArr();
}
// 没有泛型的集合定义,的问题:

// 1. 可以在集合中存储多个数据类型,在进行集合遍历时,需要通过强制类型转换得到集合中的元素类型
// 2. 因为集合中存储的存储的类型不一致,强制类型转换时报错
public static void getArr() {
ArrayList arr = new ArrayList();
arr.add(“a”);// String
arr.add(“b”);
arr.add(“c”);
arr.add(12);// Integer

	for(int i = 0 ; i < arr.size() ; i ++) {
		
		Object obj = arr.get(i);
		String s = (String)obj ;
		System.out.println(s);
	}	
}
// 有泛型的集合定义: 1. 确定集合的数据类型,提高代码的安全性  2. 获取元素不需要强制类型转换,比较方便	
public  static void getFanXingArr() {
	// 定义ArrayList加上泛型
	// 表示: String类型就是arr这个对象的泛型,属于一个已知的类型
	// 使得集合ArrayList中只能存储String类型
	ArrayList<String>  arr = new ArrayList<String>();
	arr.add("a");
	arr.add("b");
	arr.add("hello");
	//arr.add(1234);
			
	Iterator<String> it = arr.iterator();
	while(it.hasNext()) {			
		String s = it.next();
		System.out.println(s);
	}		
}

}

泛型使用的注意事项:

  1. 定义的泛型类型,前后必须要保持一致
  2. 泛型的推测: 从JDK1.7版本开始,后面的泛型类型可以省略,默认与前面泛型保持一致,
    甚至,可以将 都省略掉

代码
// 泛型的注意事项
public static void fanXingAttion() {
// 1. 定义的泛型类型,前后必须要保持一致
// ArrayList arr = new ArrayList(); 错误代码
ArrayList arr = new ArrayList();
// ArrayList arr3 = new ArrayList(); 错误代码

	// 2. 泛型的推测: 从JDK1.7版本开始,后面的泛型类型可以省略,默认与前面泛型保持一致
	// 甚至,可以将<Integer>  都省略掉
	ArrayList<String> arr1 = new ArrayList<>();
	ArrayList<String> arr2 = new ArrayList();		
}

1.3 带有泛型的类
泛型类: 类上是带有泛型的
泛型类的定义方式:
修饰符 class 类名<泛型类型1,泛型类型2…>{

}

泛型类的使用:

  1. 泛型类型在定义时,定义规则: 是一个符合标识符规范的大写字母,泛型类型可以定义多个
  2. 泛型定义时机: 在创建类对象时,指定泛型的具体类型
  3. 泛型声明具体类型之后,就是一个已知的类型,可以在整个类中使用

代码
package com.zgjy.fanxing;

import java.util.ArrayList;

// 定义一个带有泛型的类
// 2. 泛型T在整个类中都可以使用
public class FanXingClass {
// 成员变量 ArrayList
private ArrayList arr = new ArrayList();

// 向成员变量所表示的集合中添加元素,在方法中使用了类上的泛型类型T
public T addElements(T t) {
	arr.add(t);
	return t;
}

public static void main(String[] args) {
	// 1. 创建类对象时,指定泛型T的具体类型
	FanXingClass<String> class1 = new FanXingClass<>();
	String s = class1.addElements("abc");
	String s1 = class1.addElements("world");
	System.out.println(s);// abc
	System.out.println(s1);// world
	System.out.println(class1.arr);// [abc, world]		
}

}

1.4带有泛型的方法
泛型的方法: 方法上面带有泛型
泛型方法的定义:
修饰符 <泛型类型1,泛型类型2,…> 返回值类型 方法名(参数列表){

}

泛型方法的使用:

  1. 方法上的泛型,可以在方法内部当做已知类型使用
  2. 非静态的方法,如果没有定义方法的泛型,可以使用类中的泛型
  3. 静态方法,只能在方法上自己定义泛型. 如果静态方法上没有定义泛型,也不能使用类上的泛型(类上的泛型,在创建类对象时确定具体类型,静态优先于对象存在,因此静态不能使用类上面的泛型)

代码
package com.zgjy.fanxing;
import java.util.ArrayList;
public class FanXingMethod {

public static void main(String[] args) {
	FanXingMethod.getArr("a");
	FanXingMethod.getArr("b");
}

// 静态方法不能使用类上的泛型E,原因: 静态中不能使用非静态的类型
public static <T> void getArr(T t) {
	ArrayList<T> list = new ArrayList();
	list.add(t);
	System.out.println(list);		
}

}

1.5带有泛型的接口
典型案例: Collection Iterator
泛型接口的定义:
修饰符 interface 接口名<泛型类型1,泛型类型2…>{

}

泛型接口的使用:

  1. 接口中定义的泛型类型,可以作为已知类型在接口中使用
  2. 接口的实现类
  1. 实现类不带有泛型,要求现实时,接口中的泛型具体类型需要制定好
    class impl implements MyInterface{

}
2) 实现类带有泛型的类,接口中不需要指定泛型

class impl implements MyInterface{

}

代码
package com.zgjy.fanxing;
// 定义一个带有泛型的接口
// 1. 没有泛型的实现类 2. 带有泛型的实现类
public interface FanXingInterface {
public abstract void getT(T t);
}

// 没有泛型的实现类
class ShiXian1 implements FanXingInterface{

@Override
public void getT(String t) {
	// TODO Auto-generated method stub
	
}		

}

// 带有泛型的实现类
class ShiXian2 implements FanXingInterface{

@Override
public void getT(T t) {
	// TODO Auto-generated method stub
	
}	

}

1.6 泛型的通配符和泛型擦除(了解)

  1. 泛型的通配符: ? , 匹配任意类型的泛型
    ArrayList<?> arr = new ArrayList();
    ArrayList<?> arr1 = new ArrayList();
  2. addAll(Collection<? extends E> c) : 方法参数的集合,具有泛型,方法调用时,可以输入泛型E以及泛型的所有的子类
  3. Comparator<? super E> : 表示输入的泛型可有是E泛型或者是E的父类泛型

泛型擦除:

  1. 代码编写的时候,定义了泛型,使用了泛型,但是在编译的.class文件中,是没有泛型的,称这种现象为泛型的擦除,泛型就是为了在代码的编写环节提高代码的安全性

  2. Set 集合
    2.1 Set集合的介绍
    Set接口是Collection接口的子接口, 来自JDK java.util.Set
    Set 集合的特点:

  3. 无序: 集合中元素的存入顺序和元素的取出顺序不一致

  4. 没有索引: 只能使用Collection中的方法进行元素的操作

  5. 不存储重复元素(元素唯一): 相同的元素在set集合中只能存储一个

List 集合特点:

  1. 有序: 集合中元素的存入顺序与元素的取出顺序保持一致
  2. 有索引: 可以通过索引获取到集合中的元素, 0 ----- 集合长度(size())-1
  3. 可存储重复元素 : 根据不同索引位置区分重复元素

Set集合是一个接口,需要通过实现类操作Set中方法, HashSet
Set set = new HashSet();// 接口的多态性

代码
package com.zgjy.set;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

public class SetDemo {

public static void main(String[] args) {
	// 创建一个Set集合
	Set<String> set = new HashSet<>();
	// 向set集合中添加元素
	set.add("a");
	set.add("cd");
	set.add("dd");
	// 元素的存取无序
	System.out.println(set);// [dd, a, cd]
	
	set.add("cd");
	set.add("hello");
	set.add("a");
	System.out.println("-----"+set);//[dd, a, cd, hello]
	
	ArrayList<String> list = new ArrayList<>();
	// 向list集合中添加元素
	list.add("a");
	list.add("cd");
	list.add("dd");
	// 元素的存取无序
	//System.out.println(list);// [dd, a, cd]
			
	list.add("cd");
	list.add("hello");
	list.add("a");
	System.out.println("++++++++++"+list);//[dd, a, cd, hello]
}

}

2.2 Set集合的遍历方式

  1. Collection接口中,方法toArray() : 将一个集合转换成一个Object类型的数组,遍历数组回去到集合中的每一个元素
  2. Collection 接口中,方法toArray(T[] t) : 将一个集合中的元素放置到参数的T[]中,进行T[] 遍历,得到的每一个元素类型都是T类型,避免在数组循环时的强制类型转换
  3. 迭代器遍历 : 通过集合中重写的iterator() 方法,获取到迭代器对象Iterator<集合中存储的数据类型>, 通过Iterator的方法, hasNext() 集合中是否有下一个元素, 如果有 next() 获取到这个元素
    说明: 迭代器,不论集合中是否有索引,都可以使用迭代器
    原理: 获取集合中的元素,元素是否带有索引迭代器不关注,只获取元素
  4. 增强for : for循环的增强表示方式,forEach (重点掌握)

增强for的语法格式:
for(数据类型 变量名 : 集合或者数组){
// 变量就是获取到集合或者是数组中的每一个元素

}

说明:

  1. 集合(List,Set)或者数组,表示的是将要被遍历的容器
  2. 数据类型 : 表示集合或者数组中存储的数据类型
  3. 变量名 : 每次循环获取到的容器中的元素的表示方式

注意: 增强for 对于集合或者是数组是否有索引无要求,将容器中的每一个元素获取到
增强for底层就是使用迭代器的原理来实现
增强for 也会发生并发修改异常(使用增强for不要向集合中添加元素)

代码
package com.zgjy.set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetFor {

public static void main(String[] args) {
	Set<String> set = new HashSet();
	set.add("a");
	set.add("b");
	set.add("c");
	set.add("d");
	
	//getSet1(set);
	//getSet2(set);
	// getSet3(set);
	getSet4(set);
}
// 1. Set集合的遍历: toArray()-----> Object[]
public static void getSet1(Set<String> set) {
	Object[] obj = set.toArray();
	// 遍历数组
	for(int i = 0 ; i < obj.length ; i ++) {
		
		Object ob = obj[i];
		// 多态的向下转型
		String s = (String)ob;
		System.out.println(s);// a b c d
	}	
}

// 2. Set集合的第二种遍历方式: toArray(T[] t)
public static void getSet2(Set<String> set) {
	// 需要参数T[],先创建一个数组,因为set中时String类型的元素,创建String[],
	// 数组大小设置为set集合中的元素的大小
	String[] ss = new String[set.size()];
	
	String[] ss1 = set.toArray(ss);
	
	for( int i = 0 ; i < ss1.length ; i ++) {
		String s = ss1[i];
		System.out.println("222---"+s);// 
	}
}

// 3. 迭代器遍历方式
public static void getSet3(Set<String> set) {
	  //1 . 获取到迭代器对象
	   Iterator<String> it= set.iterator();
	   // 2. 循环获取集合中的每一个元素
	   while(it.hasNext()) { 
		  String s = it.next();
		  System.out.println("===="+s);// a  b  c  d 
	   }
  }

// 4. 增强for进行set集合的遍历
public static void getSet4(Set<String> set) {
	for(String s : set) {// 将集合中的每一个元素直接获取到,元素使用变量s表示	
		System.out.println("******"+s);
	}	
}		

}

2.3 Set集合保证元素唯一性
2.3.1 Set集合存储JDK已经写好的数据类型
JDK已经预置好的引用数据类型,存储在set集合中可以有效去重复
JDK中的引用数据类型,都是重写过hashCode和 equals方法

代码
package com.zgjy.set;

import java.util.HashSet;
import java.util.Set;

public class SetOnly {

public static void main(String[] args) {
	setDemo1();
}

// Set集合存储JDK预置好的数据类型
public static void setDemo1() {
	Set<String> set = new HashSet<>();
	set.add("a");
	set.add("b");
	set.add("a");
	set.add("a");
	set.add("c");
	System.out.println(set); // [a, b, c]
	
	Set<Integer> set1 = new HashSet<>();
	set1.add(1);
	set1.add(11);
	set1.add(2);
	set1.add(11);
	set1.add(1);
	System.out.println(set1);// [1, 2, 11]
}

}

2.3.2 Set集合存储自定义类型
Set集合中存储的自定义的引用数据类型,要想做到根据对象中的成员变量的值进行去重复功能,在自定义类型中,重写hashCode 和 equals

  1. 关注Object类中,hashCode 和 equals 两个方法,因为这两个方法都是判断是否是同一个对象的方法
    hashCode : 获取每一个对象的int 类型的数值,Object源代码中,每一个new对象都有一个不同的int 类型的返回值
    equals : 用于比较两个对象是否相等,Object源码,比较两个对象的地址, 使用== 比较

  2. 自定义类型中,重写hashCode 和 equals
    重写hashCode功能 : 将类中的成员变量的值获取到,转换成int类型的数值
    重写equals 功能: 就是比较两个对象的成员变量值是否相等

发现重写hashCode 和 equals 方法后,自定义的数据类型对象,可以将相同成员变量的对象进行去重复操作

代码
package com.zgjy.set;
public class Person {
private String name;
private int 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;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return “Person [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 == 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;
}

}

package com.zgjy.set;
import java.util.HashSet;
import java.util.Set;
public class SetOnly {
public static void main(String[] args) {
setDemo2();
}

// Set集合中存储自定义的数据类型
public static void setDemo2() {
	// 要求: Person 对象存储在set集合时,不同的对象 name 和 age 的值都不相等
	Set<Person> set = new HashSet<>();
	set.add(new Person("QQ",12));
	set.add(new Person("QQ",12));
	set.add(new Person("QQ糖",12));
	set.add(new Person("大美",25));
	System.out.println(set);	
}

}

2.3.3 Set集合的保证元素唯一原理
Set集合底层数组 + 链表的结构,通过hashCode和equals两个方法进行元素唯一性的验证

在这里插入图片描述

2.4 LinkedHashSet
HsahSet的一个子类,LinkedHashSet 进行元素存储,能够保证存入的顺序和元素取出的顺序保持一致,其他方法,与hashSet基本上一致

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值