在将ArrayList底层代码之前,我先讲两个东西一个是“Object" 一个是”泛型“
Object
含义:
1 Object 是所有引用类直接或间接的父类(这里的"父类“,是方便大家理解。准确的说是”超类“或者”基类“)
2 Object 是所以 引用数据类型(常见的引用数据类型有:数组,String,枚举,接口)的父类
特点:
1 没有属性(成员变量)
2没有父类(本身就是父类),可以被继承
应用:
Object 类中,常见的方法:
equals()(用于判断两个对象是否相等)
代码如下:
public boolean equals(Object obj) {
return (this == obj);
}
toString()(用于返回对象的字符串表示)
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
hashCode()(用于返回对象的哈希码)
getClass()(用于返回对象的字节码对象)等。这些方法可以被所有的子类继承并使用。
举一个例子:我先创建一个动物类的对象,现在如果我要调用getClass方法,会发生什么呢?
注意:当你使用getClass 方法时,返回所在对象的对象类型地址(一般格式是 :class 空格 包名点类名)
泛型
含义:限定数据类型,通常我们把"泛型"理解成“数据类型”的变量
所以在使用泛型时,往往是先声明变量,用<>
格式:<E>
E,K,V,T都 可以用来表示变量(这里的大写字母表示为,数据类型的的变量。如 int a 一样。)默认情况下,泛型表示为 Object类型。
注意:给这些变量赋值时,都是类类型。(也就是说,基本数据类型,不行。如< int >,不行!
为什么?
1 泛型(数据类型变量)默认是Object类型,所以即使你要修改类型,也是内部修改,范围还是在Object的范畴里
2从java的角度,“任何事物,皆对象”,那基本数据类型可以创建对象吗?(答案是,不行的!,但又为了证明“任何事物,皆对象”这个理念,推出了 包装类 这一概念。所以这也是为什么,即使我们 存入的数字,也不会报错的---自动装箱。
为什么我要使用泛型?
大家看例题
我使用ArrayList集合,存入数据,这些数据有字符串“1245”,整型 245,浮点型 12.5,现在我要知道存入集合字符串的长度。
在我们没学泛型之前,代码如下
ArrayList<Object> list = new ArrayList<>();
list.add(245);
list.add("1245");
list.add(12.5);
//获得 字符串1245的长度
for (int i=0;i<list.size();i++){
Object o = list.get(i );
if (o instanceof String){
String s=(String)o;
System.out.println(s .length());
// instanceof 是判断变量原本是什么类型
}
else {
continue;
}
}
通过观察代码,你就会发现要想知道原本存入集合的字符串长度,就要经过一下步骤
1 判断存入的数据是否是字符串
2向下转型(将原本的Object类型 转变为 String 类型
3最后才是通过方法,获得字符串的长度
这样,你会发现,原本存入的字符串,当再次使用时,还要经过这么的繁琐的步骤,有没有更简单的,更轻松的步骤或方法呢?答案:是有的,因此出现了"泛型”。
这一次,我使用泛型,来存入数据,得到字符串“1245"的长度
代码如下
ArrayList<String> list = new ArrayList<>();
list.add("1245");
// list.add(245);
// list.add(12.5);
//获得 字符串1245的长度
String s1 = list.get(0);
System.out.println(s1.length());
大家可能会想,原本存入 集合的整型和浮点型,为什么要省略呢?
大家 如果,有这个疑问,是正确的。
原因是:编译会报错!!!“我之前说把"泛型“看做一个数据类型的变量方面大家理解。在这里当我们给"泛型”声明为字符串时存入集合的元素都是字符串,所以当我们要存入其他不是字符串类型时,会发生编译错误。
特点:
1 把原本运行时的错误,提前到编译时,大大提高了正确性
2 给参数限定了范围,在储存或传参中,规定好了目标类型。
实例:
1创建一个学生类, 包含下列属性, 姓名, 学号, 分数, 出生日期
创建多个学生对象, 保存到List集合中,完成下列功能:
- 找到学号最小的
- 找出分数最大的
- 根据分数的降序排序
- 扩展: 如果想根据出生日期的降序排序, 怎么实现
package cnt2;
//定义学生类,确定学生的属性和方法
public class Student {
private String name;
private String id;
private double score;
private int born;
public Student(String name, String id, double score, int born) {
this.name = name;
this.id = id;
this.score = score;
this.born = born;
}
public Student() {
}
public void setName(String name) {
this.name = name;
}
public void setId(String id) {
this.id = id;
}
public void setScore(double score) {
this.score = score;
}
public void setBorn(int born) {
this.born = born;
}
public String getName() {
return name;
}
public String getId() {
return id;
}
public double getScore() {
return score;
}
public int getBorn() {
return born;
}
}
//测试类
public class Demo2Test {
public static void main(String[] args) {
Student student1 = new Student("张三","1",98,200208);
Student student2 = new Student("李四","2",92,200308);
Student student3 = new Student("王五","3",78,200404);
Student student4 = new Student("赵六","4",80,200103);
Student student5 = new Student("宋奇","5",72,200504);
Student student6 = new Student("刘八","6",86,200203);
ArrayList<Student> list = new ArrayList<>();
list.add(student1);
list.add(student2);
list.add(student3);
list.add(student4);
list.add(student5);
list.add(student6);
//1找到学号最小的
Student s=smallestid(list);
System.out.println("学号最小的"+s.getId());
//2找到分数最大的
double srcore=smallestScore(list);
System.out.println("分数最大的"+srcore);
//3根据分数的降序排序
System.out.println("分数的降序排序");
downWay(list);
//4 扩展: 如果想根据出生日期的降序排序, 怎么实现
System.out.println("根据出生日期的降序排序");
downWay1(list);
}
private static void downWay1(ArrayList<Student> list) {
int arr[]=new int [list.size()];
for (int i = 0; i <arr.length ; i++) {
arr[i]=list.get(i).getBorn();
}
for (int i = 0; i <list.size() ; i++) {
for (int j = 0; j <list.size()-i-1 ; j++) {
if (arr[j]>arr[j+1]){
int tep=0;
tep=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tep;
}
}
}
for (int i = 0; i <arr.length ; i++) {
System.out.println(arr[i]+" ");
}
}
private static void downWay(ArrayList<Student> list) {
double arr[]=new double[list.size()];
for (int i = 0; i <arr.length ; i++) {
arr[i]=list.get(i).getScore();
}
for (int i = 0; i <list.size() ; i++) {
for (int j = 0; j <list.size()-i-1 ; j++) {
if (arr[j]<arr[j+1]){
double tep=0;
tep=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tep;
}
}
}
for (int i = 0; i <arr.length ; i++) {
System.out.println(arr[i]+" ");
}
}
private static Student smallestid(ArrayList<Student> list) {
Student student ;
String minId=list.get(0).getId();
student=list.get(0);
for (int i = 1; i <list.size() ; i++) {
if (Integer.parseInt(minId)>Integer.parseInt(list.get(i).getId())){
// minId=list.get(i).getId();
student=list.get(i);
}
}
return student;
}
private static double smallestScore(ArrayList<Student> list) {
//
double maxScore=list.get(0).getScore();
for (int i = 1; i <list.size() ; i++) {
if (maxScore<list.get(i).getScore()){
maxScore=list.get(i).getScore();
}
}
return maxScore;
}
}
通配符:
含义
通配符 用?表示。表示你不确定的类型,但是控制在某个范围内的。
1 ? extend E ,表示可以传递E或E的所有子类
2 ? super E ,表示可以传递E或E的所有父类
应用场景
1如果,我们在定义类,方法,接口,时候,不确定类型,就可以定义泛型类,泛型方法,泛型接口
2如果类型不确定,但是知道,只能传递某个限承体系的,就可以使用泛型的通配符
代码演示
package cnt3;
import java.util.ArrayList;
public class Demo1 {
public static void main(String[] args) {
ArrayList<Ye> list = new ArrayList<>();
ArrayList<Fu> list1 = new ArrayList<>();
ArrayList<Zi> list2 = new ArrayList<>();
method(list);
method(list1);
method(list2);
}
//通配符 用?表示。表示你不确定的类型,但是控制在某个范围内的
//? extend E ,表示可以传递E或E的所以子类
//? super E ,表示可以传递E或E的所以父类
//应用场景
//如果,我们在定义类,方法,接口,时候,不确定类型,就可以定义泛型类,泛型方法,泛型接口
//如果类型不确定,但是知道,只能传递某个限承体系的,就可以使用泛型的通配符
public static void method (ArrayList<? extends Fu> list){
//表示 Fu的所有子类和本身
}
public static void method (ArrayList<? super Fu> list){
//表示 Fu的所有父类和本身
}
}
class Ye{
}
class Fu extends Ye{
}
class Zi extends Fu{
}
实例:
测试类代码
package cnt4;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
ArrayList<LIHuaCat> list1 = new ArrayList<>();
list1.add(new LIHuaCat());
ArrayList<BoShiCat> list2 = new ArrayList<>();
list2.add(new BoShiCat());
ArrayList<YellowDog> list3 = new ArrayList<>();
list3.add(new YellowDog());
ArrayList<BlackDog> list4 = new ArrayList<>();
list4.add(new BlackDog());
keepPet(list2);
keepPet(list1);
keepPet(list3);
keepPet(list4);
}
//可以养猫,不能养狗
// private static void keepPet(ArrayList<? extends Cat> list) {
// if (list.get(0) instanceof LIHuaCat){
// list.get(0).eat();
// }
// else {
// list.get(0).eat();
//
// }
// }
//可以养狗,不能养猫
// private static void keepPet(ArrayList<? extends Dog> list) {
// if (list.get(0) instanceof LIHuaCat){
// list.get(0).eat();
// }
// else {
// list.get(0).eat();
//
// }
//
//
// }
//只要是动物都可以
private static void keepPet(ArrayList<? extends Animal> list) {
list.get(0);
}
}
ArrayList底层代码分析,下一篇阐述。