面向对象先导学习笔记
经过了Python、C语言和数据结构的学习,感觉对于Java这门新学习的语言上手速度明显快了许多。在学习Java的过程中,个人觉得Java的语法规则在很大程度上与C类似,但是在设计程序和具体实现的过程中,更偏向于Python的思路,尤其是对于方法的调用和自带数据结构的使用方面。
数据类型的Java实现
Java自带了大量的数据类型,在完成作业的过程中,个人尝试通过手写二叉树完成问题,但是与Java自带的数据结构相比,无论是在稳定性和运行速度方面都有所欠缺。但是通过自己的摸索和尝试,在一定程度上加深了对于数据结构本身和Java语法的了解。
例如,以二叉树为例,C语言的二叉树构造方法如下:
1 typedef struct Btree 2 { 3 int n; 4 struct Btree *lnode, *rnode; 5 }btree;
在C语言中,左右子树是依靠指针,将地址存储在节点中,而在Java中没有指针的概念,但是可以在类中包含同一个类的数据,在C语言中,在 struct 中包含同一个 struct 类型的数据是不被允许的。Java实现二叉树时,直接在节点中存储左右节点本身,使用层层嵌套的方式实现二叉树。
1 public class Node 2 { 3 int n; 4 Node lnode; 5 Node rnode; 6 public Node() 7 { 8 this.n = 0; 9 this.lnode = null; 10 this.rnode = null; 11 } 12 }
以二叉树为例,其它数据类型的构造方法与此类似,涉及到的算法大同小异,下面是Java构造的BST树及其在进行插入、查找和遍历等操作时的算法:
1 import java.util.Vector; 2 3 public class Node 4 { 5 int n; 6 Node lnode; 7 Node rnode; 8 public Node() 9 { 10 this.n = 0; 11 this.lnode = null; 12 this.rnode = null; 13 } 14 15 public int cmp(int s) 16 { 17 if (n < s) 18 return -1; 19 else if (n == s) 20 return 0; 21 else 22 return 1; 23 } 24 25 public Node getLnode() 26 { 27 return this.lnode; 28 } 29 30 public Node getRnode() 31 { 32 return this.rnode; 33 } 34 35 public Node setLnode(Node s) 36 { 37 this.lnode = s; 38 return this.lnode; 39 } 40 41 public Node setRnode(Node s) 42 { 43 this.rnode = s; 44 return this.rnode; 45 } 46 47 } 48 49 50 public class BST 51 { 52 Node root; 53 54 public BST() 55 { 56 this.root = null; 57 } 58 59 public BST(Node r) 60 { 61 this.root = r; 62 } 63 64 public void insert(Node p, int i) 65 { 66 if (this.root == null) 67 { 68 this.root = new Node(i); 69 return; 70 } 71 else 72 { 73 int result = p.cmp(i); 74 if (result > 0) 75 { 76 if (p.getLnode() == null) 77 { 78 Node r = new Node(i); 79 p.setLnode(r); 80 return; 81 } 82 else 83 insert(p.getLnode(), i); 84 } 85 else 86 { 87 if (p.getRnode() == null) 88 { 89 Node r = new Node(i); 90 p.setRnode(r); 91 return; 92 } 93 else 94 insert(p.getRnode(), i); 95 } 96 } 97 } 98 99 public void printTree(Node p) 100 { 101 if (p.getLnode() != null) 102 { 103 printTree(p.getLnode()); 104 } 105 p.print();//打印该节点数据 106 if (p.getRnode() != null) 107 { 108 printTree(p.getRnode()); 109 } 110 return; 111 } 112 113 public void search(Node p, String s) 114 { 115 if (p == null) 116 { 117 return; 118 } 119 else 120 { 121 if (p.cmp(s) > 0) 122 { 123 // 查左子树 124 search(p.getLnode(), s); 125 } 126 else if (p.cmp(s) < 0) 127 { 128 // 查右子树 129 search(p.getRnode(), s); 130 } 131 else 132 { 133 // 找到该值 134 p.print(); 135 return; 136 } 137 } 138 } 139 140 }
Java的键盘/文件输入
在完成课上和课下作业的过程中,Java的文件输入和控制台输入同样是一个新接触到的内容,与C和Python相比较为繁琐,经过搜索和学习,以 Scanner 为例的输入实现方法如下: 在使用 Scanner 进行文件输入之前,需要 import 以下三个包:
1 import java.io.FileInputStream; 2 import java.io.FileNotFoundException; 3 import java.util.Scanner;
第二个用于处理异常,同时需要在进行文件输入操作的方法后添加异常情况处理,例如:
1 public static void main(String args[]) throws FileNotFoundException{...}
在执行操作时按照以下语法:
1 String name = "FILENAME"; 2 FileInputStream inputStream = new FileInputStream(name); 3 Scanner scan = new Scanner(inputStream, "ASCII"/*"UTF-8"*/);
对于键盘输入,只需 import Scanner 即可,创建 Scanner 的用法如下:
1 Scanner wordScanner = new Scanner(System.in);
在学习Java和完成作业的过程中,个人认为主要的难点在于从C语言到Java语言程序设计思路的转换,在使用C语言进行程序设计时,完全是依靠自己的思路,自底向上实现程序的每一个部分,而使用Java时,更多的要关注自己的想法与Java的内嵌数据类型和方法的契合度,并适当做出改变以更好的利用已有的方法。在完成最初一两次的作业时,很少使用Java自带的方法,在逐渐熟悉之后才开始较为熟练的查找方法和使用。
例如在完成第四次作业时使用的 HashMap ,与最初的构想并不完全相同,最终使用了嵌套的方式,将首单词、末单词和词频三个数据进行了存储。
第四次作业中使用了 HashMap 这一数据类型,与第三次手写的BST树相比,无论是运行的速度和程序的稳定性方面都有所提高,而且大大简化了程序设计的步骤。在对 HashMap 按 key 进行遍历时,可以按以下方法:
1 for(String key: this.node.keySet()) {...}
除此之外,在完成作业的过程中,Java对于数组长度的限制与C相比更为严格,如果数组容量过小,可能会导致数组越界的问题,如果过大也有可能导致爆内存,同时,Java没有C语言的内存分配。Java在实现动态数组时,可以使用 Vector 容器类。 使用时,需要首先进行 import :
1 import java.util.Vector;
Vector 内容纳的应该为 class 对象,因此需要创建整数数组时,应该创建 Vector<Integer> ,如下所示:
1 Vector<Integer> v; 2 v = new Vector<Integer>();
在学习的过程中,另一个比较难以理解的地方是接口,利用接口,可以间接实现Java本身所不支持的多重继承,此外也可以简化代码,体现了面向对象特性中的抽象。
接口的声明语法格式如下:
1 [可见度] interface 接口名称 [extends 其他的类名] 2 { 3 // 声明变量 4 // 抽象方法 5 }
当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。
类使用 implements 关键字实现接口。在类声明中, Implements 关键字放在 class 声明后面。
实现一个接口的语法,可以使用这个公式:
1 ...implements 接口名称[, 其他接口, 其他接口..., ...] ...
对于实现同一个接口的不同类,如果给同一个方法传递的数据类型不同,可以统一使用所有类型的父类: Object ,然后在方法内部具体判断是哪一种类型。
之前在学习Python的过程中便已经对面向对象有了初步的了解,但是更多的还是使用Python面向过程的部分来完成作业,对于面向对象的理解并不深。通过本门课程的学习,以Java这门完全面向对象的语言为工具,在学习了一门新语言的基础上,进一步加深了对于面向对象的理解,能够较为准确的完成作业,对于面向对象的特征:继承,封装和多态有了一些理解和体会。
继承
使用继承,子类就不会存在与父类重复的代码,维护性也提高,代码也更加简洁,提高代码的复用性。
多态
在完成作业的过程中,对于多态的涉及较少,对于多态的三种实现方法,重写/重载、接口、抽象类和抽象方法,所使用的几乎都是重写(Override)与重载(Overload)。 在涉及到重写时,应当适当利用 super 和 this 关键词,以防止调用与设想中不同的方法,减少错误的出现。
封装
在这一部分,主要的内容是利用 public , protected 和 private 三种关键字,对数据和方法进行隐藏,以提高程序的安全性。
private 只能在其自己的定义类中使用,而 public 可以在所有的类中使用。 protected 能够在自已的定义类以及其子类中使用。
意见和建议
- 在最初一节课上,首要的感觉就是懵,不明白需要做什么,不明白布置的要求如何完成。在完成坏境的配置后,经过一些讲解,直接要求完成一些任务,但是此时之前并没有接触过任何Java语法的我感觉无从下手,前两个任务在助教的帮助下才能完成,而后面的任务,更多的涉及到Java的方法等,当时完全没有了解,完全不能跟上进度。希望在下次开课时,能够强化对于基础语法的讲解,在开始完成任务前的讲解的课件中能够提供示例程序。在完成一个任务后,提供相应的标程以作参考。
- 在课后完成作业时,感觉主要的问题就是作业要求的不明确,难以上手,以及作业要求的朝令夕改。
通过本次课程的学习,我初步掌握了Java的语法,能够完成一些较为初步的工程任务,加深了对于面向对象的了解,相信对于大二下学期面向对象的学习都将有所帮助。