
Java动态数组二泛型1. 什么是泛型2. 定义泛型类3. 用 E 代替类型4. 不能用 E 来 new5. 使用时指定类型1. 数组引用2. 单个数据3. 构造方法参数4. 方法参数5. 返回值6. 局部变量补充三个关键字Object理解定义重写方法默认效果重写 toString()前后对比泛型1. 什么是泛型泛型说白了就是一种「类型模板」。写动态数组ZArrayList的时候我们暂时还不知道将来要装什么类型的数据——可能是Integer可能是String也可能是自定义的Student。于是先用一个占位字母通常叫E即 Element 元素顶替这个「还不知道的类型」。2. 定义泛型类publicclassZArrayListE{// 类体}来个最简单的对比普通类和泛型类都实现同一个效果// 普通类类型固定为 StringpublicclassNormalList{publicvoidadd(Strings){...}}// 泛型类类型先用 E 占位使用时再指定具体类型publicclassZArrayListE{publicvoidadd(Ee){...}}可以看到同样是add方法普通类把参数类型固定成了String所以它只能添加String类型的数据而泛型类里写的是E这个E暂时还没有确定类型所以将来使用时既可以装String也可以装Integer、Student等其他类型。区别就是普通类把类型固定泛型类先用E占位等使用的时候再确定具体类型。E叫「类型参数」就是一个占位字母你可以理解成占位符字母不一定是E写T、K、V都行只是习惯上E→ Element元素T→ Type类型K/V→ Key / Value键和值3. 用 E 代替类型publicclassZArrayListE{privateE[]elements;// 1. 成员变量数组引用类型privateEfirst;// 2. 成员变量单个数据publicZArrayList(Efirst){// 3. 构造方法参数类型this.firstfirst;}publicvoidadd(Ee){...}// 4. 普通方法参数类型publicEget(intindex){...}// 5. 方法返回值类型publicvoidshow(){Etempfirst;// 6. 局部变量类型}}在类里面凡是需要写“数据类型”的位置都可以直接用E占位。但存在两个容易犯错的地方E[]只能用来声明数组引用不能写成new E[10]下一点细讲。静态方法static里不能直接用类的E因为静态方法属于类本身还没和具体类型绑定。4. 不能用 E 来 newEenewE();// ❌ 编译错误E[]arrnewE[10];// ❌ 编译错误原因编译阶段 Java 还不知道E到底是什么类型没法给它分配确定的内存所以不能用E去 new。这也是泛型最容易犯的错误。5. 使用时指定类型先看使用时的写法// 创建对象时把 E 换成具体类型ZArrayListStringlistnewZArrayList();创建对象时E指定成什么类型类里所有E就一起变成那个类型。指定成String这个数组就专门用来存String指定成Integer就专门用来存Integer。下面把第 3 节的 6 种E一个一个拆开讲看看它们到使用阶段分别变成什么、有什么用。1. 数组引用原来的写法privateE[]elements;指定String后变成privateString[]elements;作用这是数组本体用来把多个数据存进对象里。看到private E[] elements;可能会疑惑这里并没有像方法参数add(String s)那样在括号里看到有数据传进来啊。其实成员变量不是靠“传参”那一瞬间存数据的它是对象内部的“仓库”。声明private E[] elements;只是先准备好一个数组引用相当于先把货架搭好。所以第 1 种E的意思就是给这个仓库定一个“专门放什么”。比如你写ZArrayListString就相当于给这个仓库贴了个标签这里只能放String。于是elements这个数组就变成了“字符串数组”2. 单个数据原来的写法privateEfirst;指定String后变成privateStringfirst;作用单独保存一个数据比如想记住第一个元素。理解它和数组一样都是“仓库”只不过数组是存一批这个是存一个。3. 构造方法参数原来的写法publicZArrayList(Efirst){this.firstfirst;}指定String后变成publicZArrayList(Stringfirst){this.firstfirst;}作用创建对象时规定必须传入一个String。理解new ZArrayList()的括号里只能放String// 正确ZArrayListStringlistnewZArrayList(hello);// 错误不能传 int// ZArrayListString list new ZArrayList(100);4. 方法参数原来的写法publicvoidadd(Ee){...}指定String后变成publicvoidadd(Stringe){...}作用调用add时只能往里面放String。list.add(apple);// 正确// list.add(123); // 编译报错5. 返回值原来的写法publicEget(intindex){...}指定String后变成publicStringget(intindex){...}作用从数组里取出数据时直接就是String。理解不用再自己强转Stringslist.get(0);// 直接是 String// 如果不用泛型可能还得自己转一次// String s (String) list.get(0);6. 局部变量原来的写法publicvoidshow(){Etempfirst;}指定String后变成publicvoidshow(){Stringtempfirst;}作用方法内部临时保存数据时使用。理解临时变量也要和E保持一致否则类型对不上会报错。小结这 6 种E归根到底就是三件事——存数据第 1、2 种、收数据第 3、4 种、给数据第 5、6 种。使用时指定String这三件事就都围绕String来运转。补充三个关键字我们来简单区分这三个关键字private私有只能在这个类内部使用。比如private E[] elements就是不想让外部随便乱动数据从而更安全。public公共类外面也能访问。比如public void add(E e)别人创建对象后才能调用这个方法添加数据。static静态属于类本身不依赖某个具体的对象开放。因为没有和具体对象绑定所以静态方法里不能用类的E。再补充一下staticstatic表示“属于类本身不属于某个具体对象”。类一加载静态成员就已经存在了不需要先new对象就能直接使用。Java 的程序入口也和它有关。每个 Java 程序都要从一个特殊的main方法开始运行最常用的主类写法是publicclassMain{publicstaticvoidmain(String[]args){// 所有代码从这里开始执行}}为什么main方法前面一定要写static因为程序刚启动时JVM 还没有创建任何一个对象它只能通过“类名.方法名”的方式直接调用main。如果main不是staticJVM 就找不到程序入口程序根本没法运行。竞赛中写主类记住这个固定套路就行类名一般写成Main很多 OJ在线判题系统会强制要求public class Main。main方法必须完整写成public static void main(String[] args)其中static不能漏。所以可以这样理解main是一个静态方法它属于Main类本身程序一启动还没创建任何对象JVM 就能直接调用Main.main()开始运行。Object理解定义Object是 Java 里最基础的一个类你可以把它理解成所有类的“老祖宗”。在 Java 里不管你写一个什么样的类哪怕什么都没有它都会自动继承Object。比如你写一个最简单的类publicclassStudent{// 里面什么都没写}其实它背后等价于publicclassStudentextendsObject{// Java 自动帮你继承 Object}也就是说Student、String、Integer还有我们前面写的ZArrayList它们共同的祖先都是Object。重写方法前面说过Object是所有类的“老祖宗”所以它会准备好一些通用方法让每个类都能直接用。这些方法虽然能用但往往只是“通用版”并不一定符合我们自己的需求。比如Object给我们准备了一个toString()方法作用是“把对象翻译成字符串”。但这个通用版没有太多信息默认只会告诉我们这是哪个类、以及一个看不懂的编号。好在 Java 允许我们“重写”子类可以重新写一个名字相同、参数相同、返回值相同的方法把从Object继承来的通用版本盖掉换成更适合自己的版本。重点记住一句话继承来的方法如果不满意就可以重写它。下面就用toString()来看具体怎么做。默认效果先写一个最普通的Student里面只放两个信息publicclassStudent{Stringname;intage;}这时候我们没有重写任何方法打印它StudentstunewStudent();System.out.println(stu);会看到Student1b6d3586这其实是Object默认的toString()输出类名地址编号哈希值。它知道“这是一个 Student 对象”但不知道我们真正关心的是name和age。重写 toString()现在要求变清楚我们希望打印学生时能直接看到姓名和年龄。于是我们在Student里重写toString()publicclassStudent{Stringname;intage;OverridepublicStringtoString(){returnStudent{namename, ageage};}}解释两点Override这是 Java 的标记意思是“我是在重写从父类继承来的方法不是新写一个方法”。方法名、参数、返回值都和Object里的toString()保持一致才能真正覆盖它。重写后再打印同一个对象Student{name小明, age18}现在输出就是我们想要的信息了。前后对比不重写用Object给的通用版只能看到Student1b6d3586。重写后用Student自己定制的版本能直接看到name和age。以后做动态数组时也会用同样的思路给ZArrayList重写toString()让打印整个数组时显示的是里面的元素而不是一串看不懂的编号。