在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
内部类的定义其实一点都不难理解,但是较难理解的是什么时候该用内部类?该用内部类的哪种形式?这个可能是大部分人比较难以理解的。我在这里自己实现一个Java集合中的链式线性表MyLinkedList,然后结合这个实现来发表一下我对内部类的看法。
MyLinkedList实现依赖于下列最基本的类。
class Node<E> {
E element;
Node<E> next;
public Node(E element) {
this.element = element;
}
}
现在需要考虑的是要将这个类定位成public 类,default 类,还是内部类?这个时候就需要分析这个类是用来干什么的。很明显它出现的目的就是为了服务MyLinkedList,其他类并不需要访问到这类,因此应该将这个数据这个类设计成内部类。
<font color="red">这里反问一下,不设计成内部类可以么?</font>是可以的,但是由于Node类只用于LinkedList,所以为了数据封装,应该把它设计成内部类。所以更改如下:
private class Node<E> {
E element;
Node<E> next;
public Node(E element) {
this.element = element;
}
}
内部类还有静态和非静态内部类,这个类该设计成哪种?首先要明白静态内部类和非静态内部类的区别,下面是两者的区别
- 内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用
- 非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。只能访问外部类的静态成员
- 一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面
由于Node不需要访问MyLinkedList任何实例成员变量,所以它应该设计成静态内部类。
private static class Node<E> {
E element;
Node<E> next;
public Node(E element) {
this.element = element;
}
}
下面给出MyLinkedList的实现,里面还有一个非静态内部类LinkedListIterator。这个类为什么需要设计成非静态的?其实是因为它需要访问MyLinkedList的实例成员变量private Node<E> head, tail; ,如果把它改成静态内部类,会报错。可以在IDE里试试更改成静态内部类看看报错信息。
MyLinkedList实现的接口
public interface MyList<T> extends Iterable<T> {
public void add(T t);
public void add(int index,T t);
public void clear();
public boolean contains(T t);
public T get(int index);
public int indexOf(T e);
public boolean isEmpty();
public int lastIndexOf(T t);
public boolean remove(T t);
public T remove(int index);
public Object set(int index,T t);
public int size();
}
MyLinkedList继承的父类
/**
* @author: gethin
* @create: 2018-05-22 15:21
* @description:
**/
public abstract class MyAbstrctList<E> implements MyList<E> {
protected int size = 0;
protected MyAbstrctList() {
}
protected MyAbstrctList(E[] objects) {
for (int i = 0; i < objects.length; i++) {
add(size, objects[i]);
}
}
@Override
public void add(E e) {
add(size, e);
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean remove(E e) {
if (indexOf(e) >= 0) {
remove(indexOf(e));
return true;
} else {
return false;
}
}
@Override
public int size() {
return 0;
}
}
MyLinkedList实现
/**
* @author: gethin
* @create: 2018-05-24 10:55
* @description: 我的链式线性表
**/
public class MyLinkedList<E> extends MyAbstrctList<E> {
private Node<E> head, tail;
public MyLinkedList() {
}
public MyLinkedList(E[] object) {
super(object);
}
public E getFirst() {
if (size == 0) {
return null;
} else {
return head.element;
}
}
public E getLast() {
if (size == 0) {
return null;
} else {
return tail.element;
}
}
public void addFirst(E e) {
Node<E> newNode = new Node<>(e);
newNode.next = head;
head = newNode;
size++;
if (tail == null) {
tail = head;
}
}
public void addLast(E e) {
Node<E> newNode = new Node<>(e);
if (tail == null) {
head = tail = newNode;
} else {
tail.next = newNode;
tail = tail.next;
}
size++;
}
public E removeFirst() {
if (size == 0) {
return null;
} else {
Node<E> temp = head;
head = head.next;
size--;
if (head == null) {
tail = null;
}
return temp.element;
}
}
public E removeLast() {
if (size == 0) {
return null;
} else if (size == 1) {
Node<E> temp = head;
head = tail = null;
size = 0;
return temp.element;
} else {
Node<E> current = head;
for (int i = 2; i < size - 2; i++) {
current = current.next;
}
Node<E> temp = tail;
tail = current;
tail.next = null;
size--;
return temp.element;
}
}
@Override
public void add(int index, E e) {
if (index == 0) {
addFirst(e);
} else if (index >= size) {
addLast(e);
} else {
Node<E> current = head;
for (int i = 1; i < index; i++) {
current = current.next;
}
Node<E> temp = current.next;
current.next = new Node<>(e);
current.next.next = temp;
size++;
}
}
@Override
public void clear() {
head = tail = null;
size = 0;
}
@Override
public boolean contains(E e) {
if (size == 0) return false;
Node<E> current = head;
do {
if (current.element.equals(e)) {
return true;
}
current = current.next;
} while (current != null);
return false;
}
@Override
public E get(int index) {
if (index < 0 || index >= size) {
return null;
} else {
Node<E> current = head;
for (int i = 0; i < size; i++) {
if (index == size) {
break;
}
current = current.next;
}
return current.element;
}
}
@Override
public int indexOf(E e) {
if (e == null) {
return -1;
}
int index = 0;
Node<E> current = head;
for (; index < size; index++) {
if (current.element.equals(e)) {
break;
}
current = current.next;
}
return index < size ? index : -1;
}
@Override
public int lastIndexOf(E e) {
if (e == null) {
return -1;
}
int lastIndex = -1;
Node<E> current = head;
for (int i = 0; i < size; i++) {
if (current.element.equals(e)) {
lastIndex = i;
}
current = current.next;
}
return lastIndex;
}
@Override
public E remove(int index) {
if (index == 0 || index >= size) {
return null;
} else if (index == 0) {
return removeFirst();
} else if (index == size - 1) {
return removeLast();
} else {
Node<E> previous = head;
for (int i = 1; i < index; i++) {
previous = previous.next;
}
Node<E> current = previous.next;
previous.next = current.next;
size--;
return current.element;
}
}
@Override
public E set(int index, E e) {
if (index < 0 || index > size) {
return null;
} else {
Node<E> current = head;
for (int i = 0; i < size; i++) {
if (index == i) {
break;
}
current = current.next;
}
E old = current.element;
current.element = e;
return old;
}
}
@Override
public String toString() {
StringBuilder result = new StringBuilder("[");
Node<E> current = head;
for (int i = 0; i < size; i++) {
result.append(current.element);
current = current.next;
if (current != null) {
result.append(", ");
} else {
result.append("]");
}
}
return result.toString();
}
@Override
public Iterator iterator() {
return new LinkedListIterator();
}
private class LinkedListIterator implements Iterator<E> {
private Node<E> current = head;
@Override
public void remove() {
Node<E> previous = head;
while (previous.next != current) {
previous = previous.next;
}
previous.next = previous.next.next;
size--;
}
@Override
public boolean hasNext() {
return current != null;
}
@Override
public E next() {
E e = current.element;
current = current.next;
return e;
}
}
//This class is only used in MyLinkedList,so it is private.
//This class is not need to access any instance numbers of MyLinkedList,so it is defined static
private static class Node<E> {
E element;
Node<E> next;
public Node(E element) {
this.element = element;
}
}
public static void main(String[] args) {
MyLinkedList<String> list = new MyLinkedList<>();
list.add("zhangsan");
list.add(1, "lisi");
list.addLast("wangwu");
list.add("lisi");
System.out.println(list);
System.out.println(list.contains("lisi"));
System.out.println(list.indexOf("lisi"));
System.out.println(list.lastIndexOf("lisi"));
list.set(3, "lisi2");
System.out.println(list);
Iterator iterator = list.iterator();
boolean flag = true;
while (iterator.hasNext()) {
System.out.println(iterator.next());
if (flag) {
iterator.remove();
flag = false;
}
}
System.out.println(list);
}
}
使用内部类的原因可以总结为:
1. 如果一个类只对另一个类有用,那么将它嵌入该类并将它们保持在一起是合乎逻辑的。 嵌套这样的“帮助类”使得它们的包更加简化
2. 它增加了封装:考虑两个顶级类A和B,其中B需要访问A的成员,否则这些成员将被声明为私有。通过在类A中隐藏类B,可以将A的成员声明为私有,并且B可以访问它们。 另外,B本身可以被外界隐藏起来。
3. 通过在类A中隐藏类B,可以将A的成员声明为私有,并且B可以访问它们。 另外,B本身可以被外界隐藏起来
需要更加全面了解,可以访问Oracle官方教程链接
网友评论