interface Pet { // 定义一个宠物的标准
public String getName();

public int getAge();

public String getColor();
}

//链表

public class Link {// 外部类,外部可见,只有这一个类
// 定义内部类,使得node类只能被link类使用
private class Node {// 定义的节点类
private Object data;// 保存数据
private Node next;// 引用关系

public Node(Object data) {
// 必须有数据才有node
this.data = data;
}

public void addNode(Node newnode) {
if (this.next == null) {// 当前的下一个节点为空
this.next = newnode;
} else {
this.next.addNode(newnode);
}
}

// 第一次调用(link):this=link.root
// 第二次调用(Node):this=link.root.next;
public boolean containsNode(Object data) {
if (data.equals(this.data)) {// 当前节点为要查询的节点
return true;// 不再向后查询,返回结果
} else {
if (this.next != null) {// 有后续节点
return this.next.containsNode(data);
} else {// 没有后续节点
return false;
}
}
}

public Object getNode(int index) {
// 使用当前的foot内容与要查询的索引进行比较
// 随后将foot的内容自增,目的是为了下次查询方便
if (Link.this.foot++ == index) {
return this.data;// 返回当前结果数据
} else {
return this.next.getNode(index);
}

}

public void setNode(int index, Object data) {
if (Link.this.foot++ == index) {
this.data = data;// 进行内容修改
} else {
this.next.setNode(index, data);
}
}

// 要传递上一个节点以及要删除的数据
public void removeNode(Node previous, Object data) {
if (data.equals(this.data)) {// 当前节点是要删除的节点
previous.next = this.next;
} else {// 向后继续查询
this.next.removeNode(this, data);
}
}

// 第一次调用(link):this=link.root
// 第二次调用(Node):this=link.root.next;
public void toArrayNode() {
Link.this.retArray[Link.this.foot++] = this.data;
if (this.next != null) {
this.next.toArrayNode();
}
}
}

// **********************以上为内部类*************
private Node root;
private int count = 0;// 保存元素个数
private int foot = 0;// 表示node类元素编号
private Object[] retArray;

public void add(Object data) {
if (data == null) {
return;
}
Node newnode = new Node(data);// data保存为node型
if (this.root == null) {// 当前没有根节点
this.root = newnode;// 保存根节点
} else {
// 根节点存在,其他节点交给node类处理
this.root.addNode(newnode);
}
this.count++;// 每一次保存完成之后数据量加1.
}

public int size() {
return this.count;// 取得count值。
}

public boolean isEmpty() {
return this.count == 0;
}

public boolean contains(Object data) {
// 现在没有要查询的数据,根节点也没有数据
if (data == null || this.root == null) {
return false;
}
return this.root.containsNode(data);
}

public Object get(int index) {
if (index > this.count) {// 超出了查询范围
return null;
}
this.foot = 0;// 表示从前向后查询
return this.root.getNode(index);// 将查询过程交给node类处理
}

public void set(int index, Object data) {
if (index > this.count) {
return;// 结束方法调用
}
this.foot = 0;
this.root.setNode(index, data);
}

public void remove(Object data) {
if (this.contains(data)) {// 主要功能是判断数据是否存在,存在才可以进行删除
if (data.equals(this.root.data)) {// 要删除数据是否是根节点数据
this.root = this.root.next;// 空出当前根节点
} else {// 不是根节点,此时根节点已经判断结束,从第二个节点开始判断
this.root.next.removeNode(this.root, data);
}
this.count--;// 个数要减少
}
}

public Object[] toArray() {
if (this.root == null) {
return null;
}
this.foot = 0;
this.retArray = new Object[this.count];// 开辟数组
this.root.toArrayNode();// 交给node类处理
return retArray;
}
// public static void main(String args[]) {
// Link all = new Link();
// all.add("A");// 此时可以增加任意Object子类对象,以String对象为例
// all.add("B");
// all.add("C");
// all.remove("A");
// Object data[] = all.toArray();
// for (int x = 0; x < data.length; x++) {
// String str = (String) data[x];// 向下转型,转为字符串进行输出
// System.out.println(str);//输出BC
// }
// }
}

//猫子类

//根据宠物接口的标准定义各个子类
public class Cat implements Pet {// 如果不实现宠物接口无法保存宠物信息
private String Name;
private int Age;
private String Color;

public Cat(String Name, String Color, int Age) {
this.Age = Age;
this.Name = Name;
this.Color = Color;
}

public boolean equals(Object obj) {// 覆写equals()方法
if (this == obj) {// 地址相同
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Cat)) {
return false;
}
Cat c = (Cat) obj;
if (this.Name.equals(c.Name) && this.Age == c.Age && this.Color.equals(c.Color)) {
return true;
}
return false;

}

public String getName() {
return Name;
}

public int getAge() {
return Age;
}

public String getColor() {
return Color;
}

public String toString() {
return "猫的名字 " + Name + " 颜色 " + Color + " 年龄 " + Age;
}
}

//狗子类

//根据宠物接口的标准定义各个子类
public class Dog implements Pet {// 如果不实现宠物接口无法保存宠物信息
private String Name;
private int Age;
private String Color;

public Dog(String Name, String Color, int Age) {
this.Age = Age;
this.Name = Name;
this.Color = Color;
}

public boolean equals(Object obj) {// 覆写方法
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Dog)) {
return false;
}
Dog c = (Dog) obj;
if (Name.equals(c.Name) && this.Age == c.Age && this.Color.equals(c.Color)) {
return true;
}
return false;

}

public String getName() {
return Name;
}

public int getAge() {
return Age;
}

public String getColor() {
return Color;
}

public String toString() {
return "狗的名字 " + Name + " 颜色 " + Color + " 年龄 " + Age;
}
}

//宠物商店类

//宠物商店与具体的宠物没有任何关系,它只与宠物这个
//接口(interface Pet)的标准有关
public class PetShop {// 一个宠物商店要保存有多个宠物的信息
private Link pets = new Link();// 保存的宠物信息

public void add(Pet pet) {// 上架宠物
this.pets.add(pet);// 向集合里保存数据
}

public void delete(Pet pet) {// 下架
this.pets.remove(pet);// 集合删除数据
}

// 模糊查询一定是返回多个内容
public Link search(String keyWord) {
Link result = new Link();// 保存结果
// 将集合以对象数组的形式返回,因为集合保存的是Object
// 但是我们真正要查询的数据在Pet接口对象的getName()方法的返回值
Object[] obj = this.pets.toArray();
// Pet p=(Pet)obj[];
for (Object x1 : obj) {
// for (int x = 0; x < obj.length; x++) {
Pet p = (Pet) x1;
if (p.getName().contains(keyWord)) {// 查询到了
result.add(p);// 保存满足条件的结果到集合
}
}
return result;
}
}

//测试类
public class PetShopDemo {
public static void main(String[] args) {
PetShop ps = new PetShop();
ps.add(new Cat("乐花", "花色", 3));
ps.add(new Cat("花皮", "黄色", 11));
ps.add(new Cat("喵欢", "黑色", 5));
ps.add(new Dog("旺旺", "黄色", 5));
ps.add(new Dog("欢欢", "黑色", 12));
ps.add(new Dog("花花", "花色", 9));
ps.delete(new Cat("喵欢", "黑色", 5));
Link allColor = ps.search("花");
Link allName = ps.search("黄");
Object[] obj1 = allColor.toArray();
for (int x = 0; x < obj1.length; x++) {
System.out.println(obj1[x]);// 猫的名字 乐花 颜色 花色 年龄 3
}            // 猫的名字 花皮 颜色 黄色 年龄 11
System.out.println();    // 狗的名字 花花 颜色 花色 年龄 9
Object[] obj2 = allName.toArray();
for (Object o : obj2) {   // 空指针异常
System.out.println(o);
}
}
}