Java入门(七)之面向对象-划重点
Java入门(七)之面向对象-划重点
0. 面向对象的概念
0.1 面向对象和面向过程
-
面向对象是一种软件开发方法,这种方法可以将现实中的事物抽象出来,让我们的编程模型化。
-
面向过程也是一种软件开发方法,它需要我们通过具体的,流程化的方式去解决问题
-
打个比方,我们现在要吃个饭。
- 可能我们会自己煮,所以要先去买个菜,然后洗菜切肉淘米,煮饭炒菜煲汤,然后吃掉,洗碗。这个叫做面向过程
- 可能我们会去饭店,我们只需要点菜,然后等东西上来,吃掉,然后就付钱走人。我们不用理会菜是从哪里买的,也不用理会饭是怎么做的,吃完不用洗碗。这个叫做面向对象
-
再举个程序的例子吧
-
C语言就是一个典型的面向过程的语言,我们在写程序的时候,会在main函数中写上我们的主程序,可能会调用其他的函数,甚至是其他文件的函数。
#include <stdio.h> //使用C语言生成正方形 int main(){ printRect(3); } void printRect(int size){ for(int i = 0;i<size;i++){ for(int j = 0;j<size;j++){ printf("*"); } printf("\n"); } }
-
Java使用的是面向对象编程,所以我们所有的编程都围绕着类来进行。我们不能直接调用方法,而是应该先创建实例,然后再调用实例的方法。
public class Test(){ public static void main(String[] args){ RectUtil rectUtil = new RectUtil(); rectUtil.printRect(); } } ==============下面是另一个类====================== //一个与矩形有关的工具类 public class RectUtil(){ //有一个生成矩形的方法 public void printRect(int size){ for(int i = 0;i<size;i++){ for(int j = 0;j<size;j++){ printf("*"); } printf("\n"); } } }
-
0.2 属性和方法
- 在现实中,对象指的是具体某一个事物。而在程序中,我们的对象是指我们编写的系统的某一个成分。
- 对象会包含两个内容,一个是数据,一个是动作。对象不仅能够进行操作,还能记录操作的结果。举个栗子,你会吃饭,并且吃完会变重。你的吃饭是一个动作,而体重是一个数据。
- 众所周知,类是从对象中抽象出来的,可以说:类是对具有相同特性和行为的对象的抽象。所以,类的具体化(或者说实例化)就是对象,对象的抽象化就是类。
- 类具有属性,我们通过属性来描述类的特性。
- 类具有方法,我们通过方法来描述类的一些操作,我们也可以叫它函数。
- 当类实例化为对象,类的属性可以被赋值成为对象的数据,类的方法可以被调用成为对象的一个动作,或者说操作。
- 类,也可以当做一种数据类型。
- 例如:String,Date都是一个类,同时他们也可以表示字符串,时间的数据。
- 由上面这条,我们可以明确一点,类里面的属性可以是其他的类。
- 例如:一个电脑类,它的属性可以有CPU,显卡,显示屏,而这些同样可以抽象为类,同时它们又是电脑类的属性之一。
1. 面向对象的特征
1.1 对象唯一
- 每一个对象,都是唯一的,会有一个唯一的标识,就像C语言中的指针,存储着变量的地址,类实例化成对象后,会有一个唯一的地址存放对象。
1.2 抽象性
- 指的就是将具有相同特性和行为的对象抽象成类。
1.3 三大特性——继承、封装、多态
1.3.1 继承
- 继承指的是从已经存在的类中继承到它的属性和方法,这样可以减少代码的重复。
- 父类:指的是被继承的那个类
- 子类:指的是继承父类的类。
- 在Java中,所有的类继承与Object,即所有类的父类都为Object
- 在Java中,只允许被一个类继承,目的是降低多继承带来的耦合度过高
- 我们可以通过多个接口,拓展类的功能。
1.3.2 封装
-
生活中的封装指的是将东西包裹起来
- 例如电脑机箱将内部的元件封装,我们看到的是机箱,可以使用开机按钮,而看不到内部的元件。
-
在程序设计中,我们可以将类封装起来,只提供需要的方法接口,而不需要提供具体的实现细节。
- 例如:我们实现一个翻译单词的类,我们需要做几件事
- 写一个读取单词列表的方法
- 写一个在单词列表中查找我们要翻译单词的方法
- 写一个方法整合上面两个方法,实现业务逻辑:读取单词列表 -> 查找目标 -> 返回结果
- 而在这之中,我们只需要第三个方法就可以实现翻译单词。而另外两个方法可以不暴露出来,从而让我们代码更加健壮。
- 例如:我们实现一个翻译单词的类,我们需要做几件事
-
封装有四个修饰符
范围/修饰符 类的内部 包的内部 任何位置 适用 备注 public √ √ √ 修饰类,成员属性,成员方法,内部类 protected √ √ 修饰成员属性,成员方法,内部类 不能修饰类 默认不写 √ √ 修饰类,成员属性,成员方法,内部类 private √ 修饰成员属性,成员方法,内部类 私有方法不能被继承 -
封装的原则
- 把不需要对外提供的内容都隐藏起来,把属性都隐藏起来,提供公共方法对其访问(通常使用get获取,set设置)
-
封装的结果是存在,但是不可见
1.3.3 多态
-
同名的不同方法
-
将子类对象赋值给父类变量,调用的方法为子类的方法。由此,同个类型的对象在执行同一个方法时,可以表现出多种行为特征
- 例子:QQ群中的管理员和群成员。管理员也是群成员,所以可以说群成员是管理员的子类。
- 当我在使用修改备注功能的时候,群成员只能修改自己的备注,而管理员可以修改其他人的备注。
- 同理,群主也继承于群成员,但是群主有更多的权限。
-
此时,如果你想调用父类的方法,可以使用super关键字。
-
父类中声明为static、final的方法不能被覆盖,而且声明为final的类的所有方法不允许被覆盖。
-
方法的重载
- 方法的重载是另一种实现多态的方法,它指的是在类中,定义同名的方法,但是这些方法具有不同的参数类型,参数个数,则可以实现多态。
- 使用这种方法时,当我们填入的数据类型为对应方法的类型时,就会调用该方法。
test(int i){} test(String str){} test(int i,String str){} 当我调用test(1)时,会自动的调用到第一个方法,而调用test("1")时,会自动调用到第二个方法。
2. 继承相关
2.1 抽象类
- 抽象类使用abstract class关键字来定义
- 抽象类除了不能实例化外,写法与普通类并无二致
- 由于不能实例化,抽象类只有被继承才能使用,因此一般在设计时就会决定是否使用抽象类
public abstract class AStudent{
private String id;
private String name;
private String dept;
public void study(){
System.out.println("我在学习!");
}
}
public class GoodStudent extends AStudent{
public void study(){
super().study();
System.out.println("敲代码,进大厂!");
}
}
public class BadStudent extends AStudent{
public void study(){
System.out.println("什么时候可以下课,我要去食堂抢位置了!");
}
}
2.2 接口
-
接口使用interface关键字来声明
-
接口不是类,类包含属性和方法,而接口包含要实现的类
-
接口无法被实例化,只能被实现
-
实现
- 接口中的方法是没有实现的,即只有方法名,没有方法的内容。
- 我们可以理解为,这是一个空白的田字格,告诉顶上写拼音,下边写汉字,但是写什么拼音,什么汉字可以由你自己定。
public interface Teacher [extends 这里可以继承其他接口,但是我不做示范]{
public void teaching([这里可以写变量,但是我不做示范]);
}
public class TeacherImpl implements Teacher{
//如果你实现了接口,那么类中必须有接口里所有的方法的实现
public void teaching(){
[代码内容]
}
}
3. 多态相关
3.1 构造方法
- 构造方法是类的一种特殊方法,用来初始化新的对象。
- 当我们实例化时,会写:new Student()这种写法,这里的Student为什么会有括号,因为调用了构造方法。
- 当我们不写构造方法时,会有默认的一个无参的构造方法(无参指的是没参数)
- 当我们写一个构造方法时,无参的构造方法会被覆盖,即此时没有默认的构造方法
- 因此,当我们写一个有参的构造方法时,如果还想不调用构造方法,可以再写一个空白的无参构造方法
public class test{
//构造方法与类名同名,不用定义返回值,我们可以认为返回值为这个类。
public test(){
}
//有参的构造方法
public test(int i){
}
}
-
由多态的性质,我们可以知道,构造方法可以有很多个,因为它本身也是一个方法,符合多态的特性。
-
跟普通方法不同的是,它是在类被实例化的时候调用的。
- 在没有自己写构造方法时,会默认一个无参的构造方法
- 在写了一个构造方法时,没有默认的无参构造方法。
-
我们可以将其应用在,需要给多个属性赋值的时候。
-
//如果没有构造方法 Student student = new Student(); student.id = "123456"; student.name = "小明"; //如果有构造方法 Student student = new Student("123456","小明"); student = new Student();//如果没有写无参的构造方法,此时这样写会报错
-
课后习题
-
尝试使用面向对象的思想进行编程,讲述一个小故事
-
例如:
恋爱的狮子与农夫
狮子爱上了农夫的女儿,请求农夫把女儿嫁给他。农夫既不忍心把女儿许配给野兽,又不敢拒绝,就想出一个办法
当狮子来催促的时候,农夫对他说:“我愿意把女儿嫁给你,可是我的女儿害怕你的尖牙和利爪,而且我也担心这些会伤害到她。如果你能剪掉你的利爪,并且磨平你的牙齿,我就立刻让女儿与你成婚。”
狮子高兴得不得了,说道:“只要能娶到她,什么条件我都答应,我马上按照你的意思去做!”
狮子回去后剪掉了自己尖利的爪子,在磨石上磨平了尖锐的牙齿。他打扮一新,到农夫家里迎娶新娘。可是到了农夫家门口,却发现农夫手提木棒,朝自己走来,看样子来者不善。狮子警惕地摆好了架势。
果然农夫一阵乱棒像雨点一样敲击下来,但是狮子却无力还击,因为他的爪子和牙齿全然没有任何威力。
最后狮子落荒而逃,更糟糕的是,没有了尖牙、利爪,狮子再也无法捕捉到猎物,最后饿得奄奄一息。
角色类
package domain;
/**
* @author Jennyism
* @date 2020/1/27 0027 21:47
*/
public abstract class Role {
private String name;
public void say(String words) {
System.out.println(getName() + ":" + words);
}
public void think(String feel) {
System.out.println(getName() + "觉得" + feel);
}
public void attack(Role role) {
System.out.println(getName() + "对" + role.getName() + "发起攻击");
}
public void doSomething(String some) {
System.out.println(getName() + some);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
狮子类
package domain;
/**
* @author Jennyism
* @date 2020/1/27 0027 21:52
*/
public class Lion extends Role {
private boolean claw;
private boolean canineTeeth;
public Lion(String roleName) {
setName(roleName);
System.out.println("我是一只狮子,我的名字叫" + getName() + ",我爱上了农夫的女儿");
}
public void wantMarry(Role role) {
System.out.println(getName() + "想娶" + role.getName());
}
public boolean hasClaw() {
return claw;
}
public void setClaw(boolean claw) {
if (!claw){
System.out.println(getName()+"剪掉了自己尖利的爪子!");
}
this.claw = claw;
}
public boolean hasCanineTeeth() {
return canineTeeth;
}
public void setCanineTeeth(boolean canineTeeth) {
if (!claw){
System.out.println(getName()+"在磨石上磨平了尖锐的牙齿。");
}
this.canineTeeth = canineTeeth;
}
}
农夫类
package domain;
/**
* @author Jennyism
* @date 2020/1/27 0027 22:01
*/
public class Farmer extends Role {
public Farmer(String roleName){
setName(roleName);
System.out.println("我是农夫,我的名字叫"+getName()+",狮子要娶我的女儿,可我不敢拒绝。");
System.out.println("于是我想到了一个办法。");
}
}
女儿类
package domain;
/**
* @author Jennyism
* @date 2020/1/27 0027 22:06
*/
public class Daughter extends Role {
public Daughter(String roleName){
setName(roleName);
}
}
故事讲述
package client;
import domain.Daughter;
import domain.Farmer;
import domain.Lion;
import domain.Role;
/**
* @author Administrator
*/
public class MyFirstClient {
public static void main(String[] args) {
//狮子有自己的方法,需要赋值到Lion类
Lion lion = new Lion("Lion Steve");
//女儿没有再添加新的方法,可以直接赋值给Role类
Role daughter = new Daughter("Daughter Fuck");
lion.wantMarry(daughter);
lion.say("农夫,你能把你的女儿嫁给我吗。");
Role farmer = new Farmer("Farmer Fuck");
System.out.println("=============第一段结束==========");
lion.say("农夫,你要怎样才能把女儿嫁给我!");
farmer.say("我愿意把女儿嫁给你,可是我的女儿害怕你的尖牙和利爪,而且我也担心这些会伤害到她。如果你能剪掉你的利爪,并且磨平你的牙齿,我就立刻让女儿与你成婚。");
lion.think("高兴极了");
lion.say("只要能娶到她,什么条件我都答应,我马上按照你的意思去做!");
System.out.println("=============第二段结束==========");
lion.setClaw(false);
lion.setCanineTeeth(false);
lion.doSomething("打扮一新,前去迎娶新娘");
farmer.doSomething("提着木棒走来!");
farmer.attack(lion);
lion.attack(farmer);
lion.doSomething("落败逃走,没有了尖牙、利爪,狮子再也无法捕捉到猎物,最后饿得奄奄一息。");
System.out.println("=============全剧终==========");
}
}