无法理解构造函数以及在另一个 class 中调用它们的原因
Trouble understanding constructors and reasons for calling them in another class
我在大学学习软件工程,我通常对面向对象编程的基本概念有相当牢固的掌握,但最近我发现自己在一些不是的概念上落后了简单易懂。
一个主要问题是我无法理解 class 构造函数;如果我不尽快将其消灭在萌芽状态,我知道这将是我的垮台。
我已经请我的导师解释了,但一定是他们解释的方式导致我没有像往常一样的 "ah-hah" 时刻。
为了帮助你帮助我,请看下面的例子,工作程序(演示链表的使用和操作):
主要class:
package root;
public class Node<E> {
private E nodeValue;
private Node<E> next;
public static void main (String[] args) {
try {
// Example 1: Create an empty list and print it.
SinglyLinkedList<Integer> list1 = new SinglyLinkedList<Integer>();
System.out.println("Example 1: Create an empty list.");
System.out.println(list1.printList());
// ----------------------------------------------------------
// Example 2: Create a list of 1 integer (1) using InsertNodeToTail.
System.out.println("\nExample 2: Create a list of 1 integer using InsertNodeToTail.");
SinglyLinkedList<Integer> list2 = new SinglyLinkedList<Integer>();
System.out.println("Before: " + list2.printList());
list2.insertNodeToTail(1);
System.out.println("After: " + list2.printList());
// ----------------------------------------------------------
// Example 3: Create a list of 1 integer (1) using InsertNodeToHead.
System.out.println("\nExample 3: Create a list of 1 integer using InsertNodeToHead.");
SinglyLinkedList list3 = new SinglyLinkedList();
System.out.println("Before: " + list3.printList());
list3.insertNodeToHead(1);
System.out.println("After: " + list3.printList());
// ----------------------------------------------------------
// Example 4: Create a list of 5 integers (1, 3, 5, 7, and 9)
// using InsertNodeToTail. Output: 1->3->5->7->9
System.out.println("\nExample 4: Create list 1->3->5->7->9 using InsertNodeToTail.");
// Create an array of 5 integers
int[] array4 = { 1, 3, 5, 7, 9 };
// Create the head node
SinglyLinkedList<Integer> list4 = new SinglyLinkedList<Integer>();
System.out.println("Before: " + list4.printList());
// Insert nodes
for (int i = 0; i < array4.length; i++)
list4.insertNodeToTail(array4[i]);
System.out.println("After: " + list4.printList());
// ----------------------------------------------------------
// Example 5: Create a list of 5 integers (1, 3, 5, 7, and 9)
// using InsertNodeToHead. Output: 1->3->5->7->9
System.out.println("\nExample 5: Create list 1->3->5->7->9 using InsertNodeToHead.");
// Create an array of 5 integers
int[] array5 = { 1, 3, 5, 7, 9 };
// Create the head node
SinglyLinkedList<Integer> list5 = new SinglyLinkedList<Integer>();
System.out.println("Before: " + list5.printList());
// Insert nodes
for (int i = array5.length - 1; i >= 0; i--)
list5.insertNodeToHead(array5[i]);
System.out.println("After: " + list5.printList());
// ----------------------------------------------------------
// Example 6: Insert new node before a current node
System.out.println("\nExample 6: Insert node 0 before node 1.");
// Use list2, insert node 0 before node 1
System.out.println("Before: " + list2.printList());
list2.insertNodeBefore(0, 1);
System.out.println("After: " + list2.printList());
// ----------------------------------------------------------
// Example 7: Insert new node before a current node
System.out.println("\nExample 7: Insert node 4 before node 5.");
// Use list4, insert node 4 before node 5
System.out.println("Before: " + list4.printList());
list4.insertNodeBefore(4, 5);
System.out.println("After: " + list4.printList());
// ----------------------------------------------------------
// Example 8: Insert new node after a current node
System.out.println("\nExample 8: Insert node 2 after node 1.");
// Use list2, insert node 2 after node 1
System.out.println("Before: " + list2.printList());
list2.insertNodeAfter(2, 1);
System.out.println("After: " + list2.printList());
// ----------------------------------------------------------
// Example 9: Insert new node after a current node
System.out.println("\nExample 9: Insert node 10 after node 9.");
// Use list4, insert node 10 after node 9
System.out.println("Before: " + list4.printList());
list4.insertNodeAfter(10, 9);
System.out.println("After: " + list4.printList());
// ----------------------------------------------------------
// Example 10: Remove node if node value is given
System.out.println("\nExample 10: Remove node 10.");
// Use list4, remove node 10
System.out.println("Before: " + list4.printList());
list4.remove(10);
System.out.println("After: " + list4.printList());
// ----------------------------------------------------------
// Example 11: Remove node that is not in the list
System.out.println("\nExample 11: Remove node 100.");
// Use list4, remove node 100
System.out.println("Before: " + list4.printList());
list4.remove(100);
System.out.println("After: " + list4.printList());
} catch (Exception e) {
e.printStackTrace();
}
}
public Node() {
}
public Node(E nVal) {
nodeValue = nVal;
}
public Node(E nVal, Node<E> nextNode) {
nodeValue = nVal;
next = nextNode;
}
public E getNodeValue() {
return nodeValue;
}
public void setNodeValue (E nVal) {
nodeValue = nVal;
}
public Node<E> getNext() {
return next;
}
public void setNext (Node<E> n) {
next = n;
}
}
子class:
package root;
import java.io.*;
public class SinglyLinkedList<E> {
private Node<E> head;
// Create an empty list
public SinglyLinkedList() {
head = null;
}
// Access to the entire linked list (read only)
public Node<E> getHead() {
return head;
}
// Insert a node with node value = nVal as the last node
public void insertNodeToTail(E nVal) {
Node<E> lastNode = new Node<E>();
lastNode.setNodeValue(nVal);
if (head == null) {
head = lastNode;
return;
}
Node<E> curr = head;
while (curr.getNext() != null) {
curr = curr.getNext();
}
curr.setNext(lastNode);
}
// Insert a node with node value = nval as the first node
public void insertNodeToHead(E nVal) {
Node<E> newHead = new Node<E>();
newHead.setNodeValue(nVal);
newHead.setNext(head);
head = newHead;
}
// Insert new node nVal to the list before current node curVal
public void insertNodeBefore(E nVal, E curVal) {
Node<E> newNode = new Node<E>(nVal);
Node<E> curr = head;
Node<E> prev = null;
if (head.getNodeValue() == curVal) {
newNode.setNext(head);
head = newNode;
return;
}
// scan until locate node or come to end of list
while (curr != null) {
// have a match
if (curr.getNodeValue() == curVal) {
// insert node
newNode.setNext(curr);
prev.setNext(newNode);
break;
} else {
// advanced curr and prev
prev = curr;
curr = curr.getNext();
}
}
}
// Insert new node nVal to the list after current node curVal
public void insertNodeAfter(E nVal, E curVal) {
Node<E> newNode = new Node<E>();
newNode.setNodeValue(nVal);
Node<E> curr = head.getNext();
Node<E> prev = head;
//scan until locate a node or come to the end of the list
while (prev != null) {
//have a match
if (prev.getNodeValue().equals(curVal)) {
//insert node
newNode.setNext(curr);
prev.setNext(newNode);
break;
} else {
//advance curr and prev
prev = curr;
curr = curr.getNext();
}
}
}
// Remove the node containing item nVal
public void remove(E nVal) throws IOException {
if (head == null) {
throw new IOException("List empty!");
} else {
Node<E> curr = head;
Node<E> prev = null;
// becomes true if we locate target
boolean foundItem = false;
// scan until locate nodeVal or come to end of list
while (curr != null && !foundItem) {
// have a match
if (curr.getNodeValue() == nVal) {
// if current node is the first node
// remove first node by moving head to next node
if (prev == null) {
head = head.getNext();
} else { // erase intermediate node
prev.setNext(curr.getNext());
}
foundItem = true;
} else {
// advanced curr and prev
prev = curr;
curr = curr.getNext();
}
}
}
}
public String printList() {
String outputList = "";
Node<E> temp = head;
if (temp == null) {
return "List empty!";
}
do {
// Print head node value
outputList += temp.getNodeValue().toString();
// Move to next node
temp = temp.getNext();
// if next node is not empty, print ->
// else print end of line then break the loop
if (temp != null) {
outputList += "->";
} else {
break;
}
} while (true);
// the loop terminates itself when it reaches to
// end of the list
return outputList;
}
}
谁能解释一下泛型 Node<E>
(主要)class 中构造函数的用途是什么?
在什么情况下应该调用它们?
如果你想创建一个新节点并且没有任何数据,你可以调用public Node() {
public Node(E nVal) {
如果想创建一个有值的新节点可以调用
Node(E nVal, Node<E> nextNode)
被调用,如果你有 nodeValue
和 nextNode
你有三个构造函数:
public Node() {
}
public Node(E nVal) {
nodeValue = nVal;
}
public Node(E nVal, Node<E> nextNode) {
nodeValue = nVal;
next = nextNode;
}
第一个是默认构造函数,不带任何参数。它实例化 Class 节点的对象。
第二个带参数(E nVal); nVal 是 E 类型,因此实例化的节点对象将是 Node 类型。
第三个构造函数有两个参数(E nVal, Node nextNode);它与第二个构造函数的作用相同,而且它设置了列表中的下一个节点 nextNode;然后,此引用存储在实例化对象的 next 变量中。
每个构造函数创建一个新的对象实例。默认构造函数不接受任何参数,如果您不提供任何您自己的代码,也不会对新对象执行任何操作。
为了方便起见,人们通常会在构造函数中使用代码创建带有参数 and/or 的构造函数,以便返回的新对象实例预先配置了一些数据。
例如,如果数据在构建后永远不会更改,这将特别有用。另一个用例是,您将获得的任何对象实例都遵守某些规则——您只能通过在构造函数中处理这些规则来安全地做到这一点,然后再提供对象实例以供使用。
我在大学学习软件工程,我通常对面向对象编程的基本概念有相当牢固的掌握,但最近我发现自己在一些不是的概念上落后了简单易懂。
一个主要问题是我无法理解 class 构造函数;如果我不尽快将其消灭在萌芽状态,我知道这将是我的垮台。
我已经请我的导师解释了,但一定是他们解释的方式导致我没有像往常一样的 "ah-hah" 时刻。
为了帮助你帮助我,请看下面的例子,工作程序(演示链表的使用和操作):
主要class:
package root;
public class Node<E> {
private E nodeValue;
private Node<E> next;
public static void main (String[] args) {
try {
// Example 1: Create an empty list and print it.
SinglyLinkedList<Integer> list1 = new SinglyLinkedList<Integer>();
System.out.println("Example 1: Create an empty list.");
System.out.println(list1.printList());
// ----------------------------------------------------------
// Example 2: Create a list of 1 integer (1) using InsertNodeToTail.
System.out.println("\nExample 2: Create a list of 1 integer using InsertNodeToTail.");
SinglyLinkedList<Integer> list2 = new SinglyLinkedList<Integer>();
System.out.println("Before: " + list2.printList());
list2.insertNodeToTail(1);
System.out.println("After: " + list2.printList());
// ----------------------------------------------------------
// Example 3: Create a list of 1 integer (1) using InsertNodeToHead.
System.out.println("\nExample 3: Create a list of 1 integer using InsertNodeToHead.");
SinglyLinkedList list3 = new SinglyLinkedList();
System.out.println("Before: " + list3.printList());
list3.insertNodeToHead(1);
System.out.println("After: " + list3.printList());
// ----------------------------------------------------------
// Example 4: Create a list of 5 integers (1, 3, 5, 7, and 9)
// using InsertNodeToTail. Output: 1->3->5->7->9
System.out.println("\nExample 4: Create list 1->3->5->7->9 using InsertNodeToTail.");
// Create an array of 5 integers
int[] array4 = { 1, 3, 5, 7, 9 };
// Create the head node
SinglyLinkedList<Integer> list4 = new SinglyLinkedList<Integer>();
System.out.println("Before: " + list4.printList());
// Insert nodes
for (int i = 0; i < array4.length; i++)
list4.insertNodeToTail(array4[i]);
System.out.println("After: " + list4.printList());
// ----------------------------------------------------------
// Example 5: Create a list of 5 integers (1, 3, 5, 7, and 9)
// using InsertNodeToHead. Output: 1->3->5->7->9
System.out.println("\nExample 5: Create list 1->3->5->7->9 using InsertNodeToHead.");
// Create an array of 5 integers
int[] array5 = { 1, 3, 5, 7, 9 };
// Create the head node
SinglyLinkedList<Integer> list5 = new SinglyLinkedList<Integer>();
System.out.println("Before: " + list5.printList());
// Insert nodes
for (int i = array5.length - 1; i >= 0; i--)
list5.insertNodeToHead(array5[i]);
System.out.println("After: " + list5.printList());
// ----------------------------------------------------------
// Example 6: Insert new node before a current node
System.out.println("\nExample 6: Insert node 0 before node 1.");
// Use list2, insert node 0 before node 1
System.out.println("Before: " + list2.printList());
list2.insertNodeBefore(0, 1);
System.out.println("After: " + list2.printList());
// ----------------------------------------------------------
// Example 7: Insert new node before a current node
System.out.println("\nExample 7: Insert node 4 before node 5.");
// Use list4, insert node 4 before node 5
System.out.println("Before: " + list4.printList());
list4.insertNodeBefore(4, 5);
System.out.println("After: " + list4.printList());
// ----------------------------------------------------------
// Example 8: Insert new node after a current node
System.out.println("\nExample 8: Insert node 2 after node 1.");
// Use list2, insert node 2 after node 1
System.out.println("Before: " + list2.printList());
list2.insertNodeAfter(2, 1);
System.out.println("After: " + list2.printList());
// ----------------------------------------------------------
// Example 9: Insert new node after a current node
System.out.println("\nExample 9: Insert node 10 after node 9.");
// Use list4, insert node 10 after node 9
System.out.println("Before: " + list4.printList());
list4.insertNodeAfter(10, 9);
System.out.println("After: " + list4.printList());
// ----------------------------------------------------------
// Example 10: Remove node if node value is given
System.out.println("\nExample 10: Remove node 10.");
// Use list4, remove node 10
System.out.println("Before: " + list4.printList());
list4.remove(10);
System.out.println("After: " + list4.printList());
// ----------------------------------------------------------
// Example 11: Remove node that is not in the list
System.out.println("\nExample 11: Remove node 100.");
// Use list4, remove node 100
System.out.println("Before: " + list4.printList());
list4.remove(100);
System.out.println("After: " + list4.printList());
} catch (Exception e) {
e.printStackTrace();
}
}
public Node() {
}
public Node(E nVal) {
nodeValue = nVal;
}
public Node(E nVal, Node<E> nextNode) {
nodeValue = nVal;
next = nextNode;
}
public E getNodeValue() {
return nodeValue;
}
public void setNodeValue (E nVal) {
nodeValue = nVal;
}
public Node<E> getNext() {
return next;
}
public void setNext (Node<E> n) {
next = n;
}
}
子class:
package root;
import java.io.*;
public class SinglyLinkedList<E> {
private Node<E> head;
// Create an empty list
public SinglyLinkedList() {
head = null;
}
// Access to the entire linked list (read only)
public Node<E> getHead() {
return head;
}
// Insert a node with node value = nVal as the last node
public void insertNodeToTail(E nVal) {
Node<E> lastNode = new Node<E>();
lastNode.setNodeValue(nVal);
if (head == null) {
head = lastNode;
return;
}
Node<E> curr = head;
while (curr.getNext() != null) {
curr = curr.getNext();
}
curr.setNext(lastNode);
}
// Insert a node with node value = nval as the first node
public void insertNodeToHead(E nVal) {
Node<E> newHead = new Node<E>();
newHead.setNodeValue(nVal);
newHead.setNext(head);
head = newHead;
}
// Insert new node nVal to the list before current node curVal
public void insertNodeBefore(E nVal, E curVal) {
Node<E> newNode = new Node<E>(nVal);
Node<E> curr = head;
Node<E> prev = null;
if (head.getNodeValue() == curVal) {
newNode.setNext(head);
head = newNode;
return;
}
// scan until locate node or come to end of list
while (curr != null) {
// have a match
if (curr.getNodeValue() == curVal) {
// insert node
newNode.setNext(curr);
prev.setNext(newNode);
break;
} else {
// advanced curr and prev
prev = curr;
curr = curr.getNext();
}
}
}
// Insert new node nVal to the list after current node curVal
public void insertNodeAfter(E nVal, E curVal) {
Node<E> newNode = new Node<E>();
newNode.setNodeValue(nVal);
Node<E> curr = head.getNext();
Node<E> prev = head;
//scan until locate a node or come to the end of the list
while (prev != null) {
//have a match
if (prev.getNodeValue().equals(curVal)) {
//insert node
newNode.setNext(curr);
prev.setNext(newNode);
break;
} else {
//advance curr and prev
prev = curr;
curr = curr.getNext();
}
}
}
// Remove the node containing item nVal
public void remove(E nVal) throws IOException {
if (head == null) {
throw new IOException("List empty!");
} else {
Node<E> curr = head;
Node<E> prev = null;
// becomes true if we locate target
boolean foundItem = false;
// scan until locate nodeVal or come to end of list
while (curr != null && !foundItem) {
// have a match
if (curr.getNodeValue() == nVal) {
// if current node is the first node
// remove first node by moving head to next node
if (prev == null) {
head = head.getNext();
} else { // erase intermediate node
prev.setNext(curr.getNext());
}
foundItem = true;
} else {
// advanced curr and prev
prev = curr;
curr = curr.getNext();
}
}
}
}
public String printList() {
String outputList = "";
Node<E> temp = head;
if (temp == null) {
return "List empty!";
}
do {
// Print head node value
outputList += temp.getNodeValue().toString();
// Move to next node
temp = temp.getNext();
// if next node is not empty, print ->
// else print end of line then break the loop
if (temp != null) {
outputList += "->";
} else {
break;
}
} while (true);
// the loop terminates itself when it reaches to
// end of the list
return outputList;
}
}
谁能解释一下泛型 Node<E>
(主要)class 中构造函数的用途是什么?
在什么情况下应该调用它们?
如果你想创建一个新节点并且没有任何数据,你可以调用public Node() {
public Node(E nVal) {
如果想创建一个有值的新节点可以调用
Node(E nVal, Node<E> nextNode)
被调用,如果你有 nodeValue
和 nextNode
你有三个构造函数:
public Node() {
}
public Node(E nVal) {
nodeValue = nVal;
}
public Node(E nVal, Node<E> nextNode) {
nodeValue = nVal;
next = nextNode;
}
第一个是默认构造函数,不带任何参数。它实例化 Class 节点的对象。
第二个带参数(E nVal); nVal 是 E 类型,因此实例化的节点对象将是 Node
第三个构造函数有两个参数(E nVal, Node nextNode);它与第二个构造函数的作用相同,而且它设置了列表中的下一个节点 nextNode;然后,此引用存储在实例化对象的 next 变量中。
每个构造函数创建一个新的对象实例。默认构造函数不接受任何参数,如果您不提供任何您自己的代码,也不会对新对象执行任何操作。
为了方便起见,人们通常会在构造函数中使用代码创建带有参数 and/or 的构造函数,以便返回的新对象实例预先配置了一些数据。
例如,如果数据在构建后永远不会更改,这将特别有用。另一个用例是,您将获得的任何对象实例都遵守某些规则——您只能通过在构造函数中处理这些规则来安全地做到这一点,然后再提供对象实例以供使用。