1. 泛型机制
1. 泛型机制概述:是一种将数据类型明确工作,推迟到创建对象或者调用方法是才去明确的一种机制
2. 泛型的好处:可以避免向下转型,也可以提高程序的扩展性
3. 泛型的语法:<类型>,<类型1,类型2…>,类型指的是引用类型
4. 类型的定义:泛型可以定义在类上,接口上,方法上
5. 泛型有效时间:泛型只在编译期有效,在运行期就擦除
2. 创建集合时使用泛型
1. 创建集合时使用引用普通类型作为泛型
import java.util.ArrayList;
public class TestDemo01 {
public static void main(String[] args) {
/**
* 在没有使用泛型时,集合中可以存储多种类型的引用元素
*/
ArrayList list1 = new ArrayList();
list1.add(new Integer(111));
list1.add(222);
list1.add("java");
list1.add(3.14);
/**
* 在创建集合时,使用泛型
* 比如说明确了集合中只能存储String类型的数据
*/
ArrayList<String> list2 = new ArrayList();
// list2.add(11); //报错,因为不是String类型
list2.add("lol");
list2.add("java");
String s = list2.get(1); //避免了向下转型
/**
* 明确集合中只能存储Integer类型
*/
ArrayList<Integer> list3 = new ArrayList();
list3.add(new Integer(11));
list3.add(new Integer(22));
list3.add(new Integer(33));
Integer integer = list3.get(2);
System.out.println(integer);
/**
* 如果需要存储多种类型的集合,泛型可以是Object
* 一般来说,一个集合只存储一种类型的数据
*/
ArrayList<Object> list4 = new ArrayList();
list4.add("java");
list4.add(123);
list4.add(3.14);
Object o = list4.get(1);
System.out.println(o);
}
}
2. 创建集合时使用类类型作为泛型
import java.util.ArrayList;
import java.util.Objects;
public class TestDemo02 {
public static void main(String[] args) {
ArrayList<LOL> list = new ArrayList<>();
list.add(new LOL("EZ",24));
list.add(new LOL("VN",30));
list.add(new LOL("MF",27));
//不用向下转型
LOL lol = list.get(2);
System.out.println(lol.getName() + "===" + lol.getAge()); //MF===27
}
}
class LOL{
private String name;
private int age;
public LOL() {
}
public LOL(String name, int age) {
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 "LOL{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LOL lol = (LOL) o;
return age == lol.age &&
Objects.equals(name, lol.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
3. 泛型类
1. 泛型类的概述:把泛型定义在类上
2. 泛型类的定义格式:public class 类名<泛型类型1,…>
3. 不使用泛型类和使用泛型类的对比
//不使用泛型类
public class TestDemo01 {
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.setObj("aaa");
MyClass myClass2 = new MyClass();
myClass2.setObj(111);
//向下转型
Object obj = myClass.getObj();
String str = (String) obj;
System.out.println(str.length()); //3
}
}
/**
* 在没有使用泛型时
* 在设计一个类的时候,为了提高程序扩展性,经常会把这个数据类型设置为Object
* 好处是提高了程序扩展性,不好处是还需要向下转型
*/
class MyClass{
private Object obj;
public Object getObj(){
return obj;
}
public void setObj(Object obj){
this.obj = obj;
}
}
=======================================================================
//使用泛型类
public class TestDemo02 {
public static void main(String[] args) {
//先设置为String类型
NewClass<String> newClass1 = new NewClass<>();
newClass1.setObj("java");
String str = newClass1.getObj();
System.out.println(str.length()); //4
//设置为Integer类型
NewClass<Integer> newClass2 = new NewClass<>();
newClass2.setObj(111);
Integer integer = newClass2.getObj();
System.out.println(integer.intValue()); //111
}
}
/**
* 设计一个类,使用泛型
* 可以提高扩展性,也可以避免向下转型
* T:代表任何数据类型
*/
class NewClass<T>{
T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
4. 泛型接口
1. 泛型接口的概述:把泛型定义在接口上
2. 泛型接口的定义格式:public interface 接口名<泛型类型>
public class TestDemo03 {
public static void main(String[] args) {
//接口上定义了泛型,在创建接口的实现类对象时明确具体类型
//匿名内部类
new MyInterface<Double, Integer>() {
@Override
public Double test(Integer integer) {
return null;
}
};
new MyInterface<Integer, String>() {
@Override
public Integer test(String s) {
return null;
}
};
//创建接口的实现类对象
MyInterfaceImpl myInterface = new MyInterfaceImpl();
Integer abc = myInterface.test("abc");
}
}
interface MyInterface<R,P>{
public abstract R test(P p);
}
//有一个具体的子类在实现接口时,这个接口上有泛型,就可以直接明确接口上的泛型
class MyInterfaceImpl implements MyInterface<Integer,String>{
@Override
public Integer test(String s) {
return null;
}
}
5. 泛型方法
1. 泛型方法的概述:把泛型定义在方法上
2. 泛型方法的定义格式:public<泛型类型> 返回值类型 方法名(泛型类型 变量名)
public class TestDemo01 {
public static void main(String[] args) {
LOL lol = new LOL();
//在调用泛型方法时,再去明确方法上的泛型具体是哪一种类型
lol.show("java");
lol.show(111);
lol.show(3.14);
/* String str = lol.show2("java");
Integer num = lol.show2(123);*/
Object o1 = lol.show3("go");
}
}
class LOL<R>{
public<T> void show(T s){
System.out.println(s);
}
public<T> T show2(T s){
System.out.println(s);
return null; //这里只能返回null,语法不报错,但没有意义
}
public<T> R show3(T s){
System.out.println(s);
return null;
}
}
6. 泛型通配符
1. 泛型通配符<?>:任意类型,如果没有明确定义,那么就是Object类型以及任意Java类
2. <? extends E>:向下限定,E及E的子类
3. <?super E>:向上限定,E及E的父类
import java.util.ArrayList;
public class TestDemo01 {
public static void main(String[] args) {
//泛型通配符 ?
ArrayList<?> list1 = new ArrayList<People>();
ArrayList<?> list2 = new ArrayList<Teacher>();
ArrayList<?> list3 = new ArrayList<Student>();
//向下限定
ArrayList<? extends People> arrayList1 = new ArrayList<People>();
ArrayList<? extends People> arrayList2 = new ArrayList<Teacher>();
ArrayList<? extends People> arrayList3 = new ArrayList<Student>();
// ArrayList<? extends People> arrayList4 = new ArrayList<Object>(); //错误 Object是People的父类
//向上限定
ArrayList<? super People> arrayList4 = new ArrayList<Object>();
ArrayList<? super People> arrayList5 = new ArrayList<People>();
ArrayList<? super Student> arrayList6 = new ArrayList<People>();
ArrayList<? super Student> arrayList7 = new ArrayList<Student>();
// ArrayList<? super Student> arrayList8 = new ArrayList<Teacher>(); //错误 Teacher不是Student的子类
}
}
class People{
}
class Teacher extends People{
}
class Student extends People{
}
7. 增强for循环
1. 增强for循环概述:简化数组和Collection集合的遍历
2. 格式:for(数据类型 变量:数组或Collection集合){
直接使用变量即可,该变量就是元素
}
3. 注意事项:
- 增强for的目标要先判断是否为null
- 在遍历途中,不能增删元素,否则会报并发修改异常
//增强for遍历字符串
public class TestDemo01 {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("java");
arrayList.add("lol");
arrayList.add("c++");
arrayList.add("IDEA");
for (String s : arrayList) {
System.out.println(s);
}
/**
* java
* lol
* c++
* IDEA
*/
}
}
=================================================================
//增强for遍历自定义对象
public class TestDemo02 {
public static void main(String[] args) {
ArrayList<LOL> list = new ArrayList<>();
list.add(new LOL("EZ",20));
list.add(new LOL("VN",23));
list.add(new LOL("MF",25));
for (LOL lol : list) {
System.out.println(lol);
}
/**
* LOL{name='EZ', age=20}
* LOL{name='VN', age=23}
* LOL{name='MF', age=25}
*/
}
}
class LOL{
private String name;
private int age;
public LOL() {
}
public LOL(String name, int age) {
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 "LOL{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
8. 可变参数
1. 可变参数的概述:当定义方法是不知道该定义多少个参数时可以用到可变参数
2. 可变参数的定义格式:(数据类型 … 变量名)
3. 注意事项:
- 这里的变量其实是一个数组
- 如果一个方法有可变参数,并且有多个参数,那么必须把可变参数放在最后一个
public class TestDemo01 {
public static void main(String[] args) {
int num1 = add(1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println(num1); //45
int num2 = add(11, 22, 33, 44, 55, 66);
System.out.println(num2); //231
}
public static int add(int ... i){ //可变参数其实是个数组,把你传过来的多个参数放到数组中
int sum = 0;
for (int ele : i) {
sum += ele;
}
return sum;
}
}