简单实现单向链表-Java(附涉及到的相关问题)

宠物商店这个题目来自阿里云大学Java基础的课程中,题目内容不是重要,这里主要是看如何实现单向链表的。

在实现链表前先思考一下几个问题:

  1. java中没有指针,怎么实现链表?
  2. 链表并不知道用户会存放什么样数据类型的数据,怎么办?
  3. 如果需要用到内部类,有哪些需要注意的?
  4. 如果遇到转型问题,有哪些需要注意的?
  5. 代码设计还是要遵循七大原则的,你怎么理解的?
interface ILink<E>{//设置泛型避免安全隐患
    public void add(E e);//增加数据
    public int size();//获取数据个数
    public boolean isEmpty();//判断是否为空集合
    public Object [] toArray();//将集合元素以数组形式返回
    public E get(int index);//根据索引获取数据
    public void set(int index,E data);//修改指定索引的数据
    public boolean contains(E data);//判断数据是否存在
    public void remove(E e);//数据删除
    public void clean();//集合清空
}
class LinkImpl<E> implements ILink<E>{
    private class Node{//Node保存节点的数据关系,而LinkImpl操作根节点
        private E data;   //保存数据
        private Node next;    //引用关系
        public Node(E data){
            this.data=data;
        }
        public void addNode(Node newNode){
            if(this.next==null){
                this.next=newNode;
            }else{
                this.next.addNode(newNode);//递归
            }
        }
        public void toArrayNode(){
            LinkImpl.this.returnData[LinkImpl.this.foot++]=this.data;
            if(this.next!=null){
                this.next.toArrayNode();
            }
        }
        public E getNode(int index){
            if(LinkImpl.this.foot++==index){
                return this.data;
            }else{
                return this.next.getNode(index);
            }
        }
        public void setNode(int index,E data){
            if(LinkImpl.this.foot++==index){
                this.data=data;
            }else{
                this.next.setNode(index,data);
            }
        }
        public boolean containsNode(E data){
            if(this.data.equals(data)){
                return true;
            }else{
                if(this.next==null){
                    return false;
                }else{
                    return this.next.containsNode(data);
                }
            }
        }
        public void removeNode(Node previous,E data){
            if(this.data.equals(data)){
                previous.data=this.next.data;
            }else{
                if(this.next!=null){
                    this.next.removeNode(this, data);
                }
            }
        }
    } 
//------------以上为内部类------------------
    private Node root;//保存根节点
    private int count;//保存数据个数
    private int foot;//操作数组的脚标
    private Object [] returnData;//保存返回的数组
    public void add(E e){
        if(e==null){
            return ;
        }
        Node newNode=new Node(e);
        if(this.root==null){
            this.root=newNode;
        }else{
            this.root.addNode(newNode);//将新节点保存在合适的位置
        }
        this.count++;
    }
    public int size(){
        return this.count;
    }
    public boolean isEmpty(){
        //return this.root==null;
        return this.count==0;
    }
    public Object [] toArray(){
        if(this.isEmpty()){
            return null;
        }
        this.foot=0;
        this.returnData=new Object[this.count];
        this.root.toArrayNode();
        return this.returnData;
    }
    public E get(int index){
        if(index>=this.count){
            return null;
        }
        this.foot=0;
        return this.root.getNode(index);
    }
    public void set(int index,E data){
        if(index>=this.count){
            return ;
        }
        this.foot=0;
        this.root.setNode(index,data);
    }
    public boolean contains(E data){
        if(data==null){
            return false;
        }
        return this.root.containsNode(data);//交给Node类判断
    }
    public void remove(E data){
        if(this.contains(data)){
            if(this.root.data.equals(data)){
                this.root=this.root.next;
            }else{
                this.root.next.removeNode(this.root, data);
            }
        }
        this.count--;
    }
    public void clean(){
        this.root=null;
        this.count=0;
    }
}
interface Pet{                    //宠物标准
    public String getName();
    public String getColor();
}
class pShop{                      //宠物商店
    private ILink<Pet> allPet=new LinkImpl<Pet>();//保存多个宠物
    public void addPet(Pet pet){
        this.allPet.add(pet);
    }
    public void deletePet(Pet pet){
        this.allPet.remove(pet);
    }
    public ILink<Pet> search(String keyword){
        ILink<Pet> resultsearch=new LinkImpl<Pet>();
        Object result[]=this.allPet.toArray();//获取全部数据
        if(result!=null){
            for(Object temp:result){
                Pet pet=(Pet) temp;//必须向下转型
                if(pet.getName().contains(keyword)||pet.getColor().contains(keyword)){
                    resultsearch.add(pet);
                }
            }
        }
        return resultsearch;
    }
}
class Cats implements Pet{
    public String neme;
    public String color;
    public Cats(){}
    public Cats(String name,String color){
        this.color=color;
        this.neme=name;
    }
    @Override
    public String getName(){
        return this.neme;
    }
    @Override
    public String getColor(){
        return this.color;
    }
    public boolean equals(Object obj){
        if(obj==null){
            return false;
        }
        if(!(obj instanceof Cats)){
            return false;
        }
        if(this==obj){
            return true;
        }
        Cats cat = (Cats) obj;  
        return this.neme.equals(cat.neme)&&this.color.equals(cat.color);
    } 
    public String toString(){
        return "宠物猫.名字: "+this.neme+", 颜色: "+this.color;
    }
}
class Dogs implements Pet{
    public String neme;
    public String color;
    public Dogs(){}
    public Dogs(String name,String color){
        this.color=color;
        this.neme=name;
    }
    @Override
    public String getName(){
        return this.neme;
    }
    @Override
    public String getColor(){
        return this.color;
    }
    public boolean equals(Object obj){
        if(obj==null){
            return false;
        }
        if(!(obj instanceof Dogs)){
            return false;
        }
        if(this==obj){
            return true;
        }
        Dogs dog = (Dogs) obj;  
        return this.neme.equals(dog.neme)&&this.color.equals(dog.color);
    } 
    public String toString(){
        return "宠物狗.名字: "+this.neme+", 颜色: "+this.color;
    }
}
public class petShop {
    public static void main(String agrs[]){
        pShop shop=new pShop();
        shop.addPet(new Cats("小猫","白色"));
        shop.addPet(new Cats("大猫","黑色"));
        shop.addPet(new Dogs("小狗","黑色"));
        shop.addPet(new Dogs("大狗","黄色"));
        shop.deletePet(new Cats("小猫","白色"));
        Object result[]= shop.search("小").toArray();
        for(Object obj:result){
            System.out.println(obj);
        }
    }
}

下面回答一下上面的六个问题:

  1. java中没有指针,怎么实现链表?
    Java中没有指针,却在很多地方运用了指针的概念——对象引用。那么当前节点如何指向后一个节点呢?在C语言中,单向链表的节点有数据域和指针域,数据域存放数据,指针域指向下一个节点的地址。其实在Java中也类似,节点之中有数据域,但还需要加上引用关系,就是添加一个节点类,表面看上去像一个节点包含着一个节点。

  2. 链表并不知道用户会存放什么样数据类型的数据,怎么办?
    有两种方法,第一个是使用Object类,第二种就是Java中的泛型了。好像两者使用起来没有太大的区别,那就谈谈泛型和Object的区别:如果使用Object类,Object类是所有类的父类,使用的时候要用到强制类型转换(这个问题到第4问还会说)转换到其他类,但如果在强制类型转换时的类型和方法返回类型不一致(比方说,方法返回的是一个String,却不注意转型成Integer),就会发生类型转换异常。使用泛型就不存在类型转换和异常了,代码鲁棒性更高。

  3. 如果需要用到内部类,有哪些需要注意的?
    内部类对象可以访问创建它的外部类对象的内容,外部类对象如果要访问内部类对象,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问。内部类如果不是static的,那么它可以访问创建它的外部类对象的所有属性内部类,如果是static的,那么它只可以访问创建它的外部类对象的所有static属性。当从外部类继承的时候,内部类是不会被覆盖的,它们是完全独立的实体,每个都在自己的命名空间内,如果从内部类中明确地继承,就可以覆盖原来内部类的方法。

  4. 如果遇到转型问题,有哪些需要注意的?
    方法的多态性:方法的重载,方法的覆写。
    对象的多态性:父子实例之间的转换处理,两种模式:对象向上转型:父类 父类实例=new 子类实例、自动完成转换;(右侧创建一个子类对象,把它当做父类来看,向上转型一定是安全的,从小范围转换成为大范围)。对象向下转型:子类 子类实例=new (子类)父类实例、强制完成转换。(这样从一般到特殊就不一定安全了,比方说子类除了继承父类外还进行了扩展,而这些是父类没有的,如果需要使用这些扩展的功能就会失败),所以可以使用instanceof运算符来在运行时判断对象是否是指定类及其父类的一个实例。
    注意,为了安全,在向下转型之前先要进行向上转型。打个比方,有超人,人,怪兽三个类,超人也属于人是人的子类,人是超人的父类。超人平时都是以普通人的身份生活的,当遇到怪兽时就变身打怪兽,而普通人装逼当做超人打怪兽,可能会被怪兽打死吧。

  5. 代码设计还是要遵循七大原则的,你怎么理解的?
    这篇文章有专门对七大原则讲解:OOP的七大原则

猜你喜欢

转载自blog.csdn.net/weixin_43845524/article/details/105489043