今日学习、
一.对象强转
1.要想让自己维护的数组里什么数据类型都能存,就要使用顶级父类
private Object[] array;
2.基本类型是没有父类的,基本类型的包装类是由父类的。因为自动装箱和拆箱机制,一般来说在需要包装类型的地方,会自动将基本数据类型转为包装类型。
3.对象转型:Object数组,虽然什么对象都能传进来,但是也只能调用Object的方法,不能调用该对象所在类的新定义的特殊的方法。
? 程序为了保证自身的安全,只允许你调用父类的方法,但是这样是满足不了需求的,如果非要使用子类的方法,怎么办?
? 可以强制转型:即使形参是父类,也能调用子类方法
public void KeepAnimal(Animal animal){
Dog dog = (Dog)animal;
? 这样一般会出问题的,如果传进来一个猫,还要被强制转换成狗,系统会报错"类型转换异常"。
此时,java引入instance of。 先判断传进来的对象是不是狗,如果是狗,再强制转换。如果是猫,就什么也不干。
public void KeepAnimal(Animal animal){
if (animal instanceof Dog) {
Dog dog = (Dog) animal;dog.eat();}
}
此时如果传进来的是猫,就会跳过if语句,系统就不会报错。
总结:使用顶级父类使这个数组什么都能存,代价是,每次取出来都要强转成相应子类才能使用子类方法。
二.泛型
相当于C++的类模板。
public class SuperArray<T>
new这个对象的时候,告诉它到底是个什么类型,系统自动把一些强转规定啥的都解决掉
注意点:类定义时,所有的未知对象类型都要写成
? public 返回值类型 fun( T data)
? 另外,返回this时,函数的返回值类型是:SuperArray****
new对象的时候
SuperArray<Cat> superArray = new SuperArray<>();
规定了SuperArray只能存Cat类型。
此时会自动将类定义里所有的泛型T,转为Cat
三.链表
int版超级链表
package com.sunjie.until;/*** @author SJ* @date 2020/10/3*/
public class Node {
public int getData() {
return data;}public void setData(int data) {
this.data = data;}private int data;private Node nextNode=null;public Node getNextNode() {
return nextNode;}public void setNextNode(Node nextNode) {
this.nextNode = nextNode;}
}
package com.sunjie.until;import java.net.BindException;/*** @author SJ* @date 2020/10/3*/
public class SuperLinked {
public static int getLength() {
return length;}public static void setLength(int length) {
SuperLinked.length = length;}public Node getTail() {
return tail;}public void setTail(Node tail) {
this.tail = tail;}public Node getHead() {
return head;}public void setHead(Node head) {
this.head = head;}//添加节点//根据下标查询数据//查询长度private Node head = null;//为了找到这个链表private Node tail = null;//为了增加节点,head不能动,要靠尾巴拉人private static int length = 0;//增加节点public SuperLinked add(int data) {
Node node = new Node();node.setData(data);if (length == 0) {
head = node;tail = node;}tail.setNextNode(node);tail = node;length++;return this;}//判断下标合法性private Boolean validate(int index) {
if (index >= length || index < 0) {
System.out.println("不存在该节点");return false;}return true;}//查询数据public void getIndexData(int index) {
Node target = head;if (validate(index)) {
//第一次进入也要判断i<indexfor (int i = 0; i < index; i++) {
target = target.getNextNode();}}System.out.println(target.getData());}//查询长度public int size() {
return getLength();}//打印链表public void print() {
Node node = head;for (int i = 0; i < length; i++) {
System.out.print(node.getData() + " ");node = node.getNextNode();}System.out.println();System.out.println("---------------");}//删除public void delete(int index) {
Node target = head;if (validate(index)) {
if (index == 0)head = head.getNextNode();else if (index == length - 1) {
//这里的边界要注意。i<length-1for (int i = 0; i < length - 1; i++) {
target = target.getNextNode();if (target.getNextNode() == tail)tail = target;}} else {
for (int i = 0; i < index - 1; i++) {
target = target.getNextNode();}target.setNextNode(target.getNextNode().getNextNode());}}length--;}}
package com.sunjie.until;/*** @author SJ* @date 2020/10/3*/
public class Test {
public static void main(String[] args) {
SuperLinked superLinked = new SuperLinked();//增加节点superLinked.add(1).add(2).add(3).add(5).add(4);superLinked.print();superLinked.getIndexData(2);superLinked.getIndexData(0);//删除头节点superLinked.delete(0);superLinked.print();//删除尾节点superLinked.delete(3);superLinked.print();//删除中间节点superLinked.delete(1);superLinked.print();}
}
测试结果
"C:\Program Files\Java\jdk1.8.0_131\bin\java.exe"...
1 2 3 5 4
---------------
3
1
2 3 5 4
---------------
2 3 5
---------------
2 5
---------------Process finished with exit code 0
将int类型的链表改成泛型
package com.sunjie.testgenericity;/*** @author SJ* @date 2020/10/3*/
public class Node<T> {
private T data;public T getData() {
return data;}public Node<T> getNextNode() {
return nextNode;}public void setNextNode(Node<T> nextNode) {
this.nextNode = nextNode;}public void setData(T data) {
this.data = data;}private Node<T> nextNode=null;}
SuperLinked类只列出部分改动部分代码:总之就是所有出现类名Node和SuperLinked的地方后面都加上
public class SuperLinked<T> {
//增加节点public SuperLinked<T> add(T data) {
Node<T> node = new Node<>();node.setData(data);if (length == 0) {
head = node;tail = node;}tail.setNextNode(node);tail = node;length++;return this;}
测试:
package com.sunjie.testgenericity;/*** @author SJ* @date 2020/10/3*/
public class Test {
public static void main(String[] args) {
SuperLinked<String> superLinked=new SuperLinked<>();superLinked.add("我").add("爱").add("吃").add("葡萄");superLinked.print();superLinked.delete(0);superLinked.print();}
}
测试结果:
"C:\Program Files\Java\jdk1.8.0_131\bin\java.exe"...
我 爱 吃 葡萄
---------------
爱 吃 葡萄
---------------Process finished with exit code 0
实现多态的思路:
我们实现过SuperArray 、SuperLinked 、Cat
SuperArray 、SuperLinked都有共同的方法 add( )、getIndexData()、size()
此时我们可以将着三个方法封装成一个更高级抽象类 abstract class Super。 该抽象类内只放申明,不给出具体实现。
SuperArray 、SuperLinked 都继承class Super,并重写抽象类内的方法。
这样有什么好处?
我们在main函数里声明。父类指针Super指向子类对象。
Super<Cat> cats = new SuperLinked<>();
此时实现的存储的数据结构就是一个链表,链表里的每一个cat都能调用Cat类的方法。
此时删除效率比较高,但查找效率低。
如果有一天,想改变数据结构,向查的快一点,我们只需要把上面那句话改成:
Super<Cat> cats = new SuperArray<>();
此时,数据结构就从链表变成了数组。
其他什么都不用改变,效果一模一样,这就是多态。
四.内部类
像上述的Node,只服务于SuperLinked一个类,外面没啥用,我们就可以把它定义成内部类,就是定义在SuperLinked类体里面。
链表里的Node是要自己封装的,java不提供
五.IDEA的junit使用
junit: 单元测试框架
标准流程(一次即可,以后可以直接用)
新建一个名叫Test的Directory,里面放测试用例
右击Test,选择Test Sources Root
其中:Sources Root——源代码根目录
? Test Sources Root——测试源代码目录
? Recourses Root——资源目录,学了jsp之后里面放的那些图片
? Test Resources Root——测试资源目录
- 在src包下建一个类
- 右击类名,Go to Test
- 点击 create new Test
- 把需要测试的方法勾上
- go to test 之后,test包就会出现和src包里一样的东西。且Test包里生成的类比src里的类名后多一个Test,证明是专门测试这个类里的方法的。(一个类可以有多个方法,他们在测试单元里都能分开执行)
- 照提示引入junit4之后,就不标红了
-
然后把org.junit删掉,用Alt+Enter引入After和Before包,Test没办法用快捷键,要手动引(我也不知道为什么),
引包也可直接 import org.junit.*; 但是.*会把所有的包都引进来。
(第二次使用就不许上述6、7两步了)
junit的使用方法就是,我们在src里写了一个add(),我们就要在test里测一个add()。
为什么交单元测试,就是我写了一个方法,但是不方便在main方法里测,因为我们一个工程可能会很大,main方法自己实现的逻辑很单一,不能在main方法里干扰别的代码,此时就要借助单元测试,单独得让这串代码跑起来。
单元测试就是一个框架,引入之后,在External Libraries里就多了Junit4,Junit4就是别人写的代码,别人半成品,拿给我们直接用,这就是框架。
此时我们就能在这里new对象进行测试。
右边的绿色的播放按钮,就能点了,就相当于我们的main方法,此时我们点击运行。
执行成功,左边有绿色的勾勾,证明这个方法被成功的执行完了,用了4ms,结果在右边的黑框框里。
如果在TestUnit里增加了新的想要测试的方法,可以直接粘贴到TestUnitTest里
只要方法前面加了@Test,前面都会有绿色的执行键 。不需要再main方法里new对象,调用方法。
当然了,我们也可以直接在测试用例里写代码,完全没问题。
package com.sun.test;import org.junit.After;
import org.junit.Before;
import org.junit.Test;import static org.junit.Assert.*;/*** @author SJ* @date 2020/10/3*/
public class TestUnitTest {
@Beforepublic void setUp() throws Exception {
System.out.println("先执行这个");}@Afterpublic void tearDown() throws Exception {
System.out.println("后执行这个");}@Testpublic void add() {
TestUnit testUnit = new TestUnit();testUnit.add();}@Testpublic void delete(){
System.out.println("测测删除");}}
@Before 是指执行下面的方法之前要先执行这个
@After 是指执行完下面的方法就执行这个
测试结果:
那么我就就可以在before里先初始化一下,往List里添点东西什么的。
例如:测试add方法,我们先new了一个list。在先行步骤里添了点数据,然后测试add方法,最后执行了遍历list操作。
package com.sun.test;import org.junit.After;
import org.junit.Before;
import org.junit.Test;import java.sql.ClientInfoStatus;
import java.util.ArrayList;
import java.util.List;import static org.junit.Assert.*;/*** @author SJ* @date 2020/10/3*/
public class TestUnitTest {
List<String> list = new ArrayList<>();@Beforepublic void setUp() throws Exception {
list.add("星星");list.add("星星");list.add("星月");}@Afterpublic void tearDown() throws Exception {
for (String s : list) {
System.out.println(s);}}@Testpublic void add() {
list.add(2,"孙悟空");}}
测试结果
"C:\Program Files\Java\jdk1.8.0_131\bin\java.exe" ...E:\project\20201003\out\production\20201003;C:\Users\admin\.m2\repository\junit\junit\4.12\junit-4.12.jar;C:\Users\admin\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.sun.test.TestUnitTest,add
星星
星星
孙悟空
星月Process finished with exit code 0
只要junit被引入了,src里也能直接 @Test 进行测试。
在企业里都是单独建test的,不建议在源代码里进行单元测试
手动引入jar包
意外情况:引入Junit 类加载不到的问题
一般来说,会自动去maven仓库里把我们所需要的框架下下来
实在不行的话:
File->Project Structure ->Libraries ->点击+ Java->选择下载好的jar包所在的目录,拖进来就行