前言
本次博客衔接上次博客,作为这一阶段Java学习的分析。上一篇博客着重介绍了Java的OO编程思维,面向对象与面向过程的区别。本篇博客重心在Java的三大技术特性,附带作业分析。
Java三大特性
封装
在面向对象程式设计方法中,封装是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。
它将类的某些信息隐藏在类的内部,不允许外部程序访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
实现封装的方式:使用访问控制符
还有伴随着出现的还有getter和setter方法。(因知识面的原因,相关的package和import先不讲解)
我们最常用的就是private,在继承中,我们继承的也是父类的非private的属性和方法。封装遵循了“封闭原则”,禁止外部直接访问内部信息。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据,必须通过严格的接口控制。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。
封装的优点:
1. 良好的封装能够减少耦合。
2. 类内部的结构可以自由修改。
3. 可以对成员变量进行更精确的控制。
4. 隐藏信息,实现细节。
继承
继承是类之间的一种关系,子类拥有父类非private的所有属性和方法,从而实现了代码的复用。继承是面向对象编程技术的基石,它允许了创建分等级层次的类。
我们为什么要用继承?
举个例子:
我们拥有多个卡片,现在需要输出每个卡片的形状,那么没有继承之前我们可能是每一个卡片类之中书写System.out.println(“这张卡片的形状是XXX”);然而我们可以继承一个Shape类,Shape类中写show(){ System.out.println(“这张卡片的形状是”+name);}这样代码的臃肿性就减少了,而且后期维护性较高。
代码示例[1]
开发动物类其中动物分别为企鹅以及老鼠,要求如下:
企鹅:属性(姓名,id),方法(吃,睡,自我介绍)
老鼠:属性(姓名,id),方法(吃,睡,自我介绍)
企鹅类 1 public class Penguin { 2 private String name; 3 private int id; 4 public Penguin(String myName, int myid) { 5 name = myName; 6 id = myid; 7 } 8 public void eat(){ 9 System.out.println(name+"正在吃"); 10 } 11 public void sleep(){ 12 System.out.println(name+"正在睡"); 13 } 14 public void introduction() { 15 System.out.println("大家好!我是" + id + "号" + name + "."); 16 } 17 }
老鼠类 1 public class Mouse { 2 private String name; 3 private int id; 4 public Mouse(String myName, int myid) { 5 name = myName; 6 id = myid; 7 } 8 public void eat(){ 9 System.out.println(name+"正在吃"); 10 } 11 public void sleep(){ 12 System.out.println(name+"正在睡"); 13 } 14 public void introduction() { 15 System.out.println("大家好!我是" + id + "号" + name + "."); 16 } 17 }
两行代码对比可以看出代码重复已经出现,使得代码臃肿且后期维护性较低,使用继承就能从根本上解决问题。提取二者的重复部分建立一个公共父类
公共父类 1 public class Animal { 2 private String name; 3 private int id; 4 public Animal(String myName, int myid) { 5 name = myName; 6 id = myid; 7 } 8 public void eat(){ 9 System.out.println(name+"正在吃"); 10 } 11 public void sleep(){ 12 System.out.println(name+"正在睡"); 13 } 14 public void introduction() { 15 System.out.println("大家好!我是" + id + "号" + name + "."); 16 } 17 }
企鹅类 1 public class Penguin extends Animal { 2 public Penguin(String myName, int myid) { 3 super(myName, myid); 4 } 5 }
老鼠类 1 public class Mouse extends Animal { 2 public Mouse(String myName, int myid) { 3 super(myName, myid); 4 } 5 }
公共父类Animal拥有企鹅和老鼠类的相同属性和方法,当企鹅和老鼠类继承公共父类之后,子类也就不会再出现重复代码,且代码的臃肿性降低,可维护性升高。
我们也可以重写重写父类的方法,及命名与父类同名的成员变量,增加代码的灵活度。我们重写的内容会覆盖掉父类的内容,如果同时需要父类和子类的内容,我们可以使用super 与 this 关键字。而final关键字声明类意义着不能继承,即最终类;或用于修饰方法,不能被重写。
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
super和this代码示例[2]
1 class Animal { 2 void eat() { 3 System.out.println("animal : eat"); 4 } 5 } 6 7 class Dog extends Animal { 8 void eat() { 9 System.out.println("dog : eat"); 10 } 11 void eatTest() { 12 this.eat(); // this 调用自己的方法 13 super.eat(); // super 调用父类方法 14 } 15 } 16 17 public class Test { 18 public static void main(String[] args) { 19 Animal a = new Animal(); 20 a.eat(); 21 Dog d = new Dog(); 22 d.eatTest(); 23 } 24 }
输出结果为:
animal : eat dog : eat animal : eat
如果我们想尽可能的隐藏代码,但是仍然允许子类的成员来访问它们。这时候可以使用protected。(关于继承权限的问题可能会在后续的学习中再进行补充)
关于继承(extends)和实现(implement)的区别
extends
1、类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。
2、在继承中可以定义属性方法,变量,常量等...
Implement
1、Implement可以有多个接口,(接口跟接口之间采用逗号分隔)。
2、在接口中只能定义全局常量(static final),和空的方法体。
3、 某个接口被类实现时,在类中一定要实现接口中的抽象方法。
继承类型[3]
多态
概念:多态是同一个行为具有多个不同表现形式或形态的能力。
Java实现多态的三个必要条件:继承、重写、向上转型
1、继承:在多态中必须存在有继承关系的子类和父类。
2、重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
3、向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
使用多态的好处之一是当调用方法时,先检查父类中是否拥有该方法,如果没有则编译错误,如果有,再调用子类的同名方法。使类的对象可以进行通用化处理,同时增加了程序的延展性。
实现多态的方式
1、基于继承实现的多态:
基于继承实现的多态主要是重写,子类的重写。多个子类的同一方法的重写可以表现出不同的行为。
2、基于接口实现的多态:
基于接口实现的多态主要是实现接口并覆盖接口中同一方法的几不同的类体现的。
继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。
作业方面
这几次作业知识迭代正变得更加符合Java的三大技术特性,不管是封装性还是继承性、多态性,这几次作业所给的UML类图也都能感觉到这些特性。
关于这几次作业的问题,除了正则表达是以外就是关于ArrayList自定义类的的使用有所不理解。
例如ArrayList<Integer>list中能很简单的理解Integer的意义并简单的使用,但是遇到了自定义的ArrayList<Card> cardList限定范围在自定义的<Card>类的范围以内,就不知道如何是好,其实理解并使用是一件比较简单事情,像integer类型的list.add(整型),整型是是整数类型的数字,而像Card类型的list.add(卡片),卡片是放入的卡片类的对象。
1 double radius = Main.input.nextDouble(); 2 Shape circle = new Circle(radius);3 Card card = new Card(circle); 4 cardList.add(card); //简单的代码示例不做过多解释,理解使用
网络上还有更加详细的Arraylist自定义类的教程,比我浅薄的表达要好的多,可以筛选并学习,当学会了Arraylist自己定义类,我感觉这两次的作业的难点也算是攻克了。
关于时间
这几次的作业花费时间最多的是水文测试的题目,因为涉及正则表达式,对于一个粗心的人来说,学习并使用正则表达式简直就是噩梦。花费时间最短的就是最近的一次作业,原因也就是没有新的知识的扩展,写起代码来也算是比较畅通。
关于测试
良好的测试并获取代码的信息式写好代码的必要条件,随着代码长度及代码难度的增加测试的重要性也慢慢的体现了出来,现在没有学会使用Debug的同学要开始加强学习了。
关于收获
这一阶段的收获一个是正则表达式的使用,另一个就是Java三大技术特性封装、继承、多态的理解和使用。
关于课程建议
作业体量、难度方面没有什么建议,关于作业的建议就是更加详细点对作业中新出现的知识点进行讲解扩充,也可以给予相关的教程方便后续的复习。
参考文献
[1][2][3]菜鸟教程https://www.runoob.com/java/java-inheritance.html