当前位置: 代码迷 >> 综合 >> 20201003—泛型链表和junit
  详细解决方案

20201003—泛型链表和junit

热度:68   发布时间:2024-03-06 00:47:50.0

今日学习、

一.对象强转

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——测试资源目录

  1. 在src包下建一个类
  1. 右击类名,Go to Test
  1. 点击 create new Test
  1. 把需要测试的方法勾上
  1. go to test 之后,test包就会出现和src包里一样的东西。且Test包里生成的类比src里的类名后多一个Test,证明是专门测试这个类里的方法的。(一个类可以有多个方法,他们在测试单元里都能分开执行)
  1. 照提示引入junit4之后,就不标红了
  1. 然后把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包所在的目录,拖进来就行

  相关解决方案