【入坑Java第四天】

面向对象

面向过程和面向对象的区别

  • “面向过程”(Procedure Oriented)是一种以过程为中心的编程思想,简称 OP。“面向过程” 也可称之为“面向记录”编程思想,就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。所以面向过程的编程方式关注点不 在“事物”上,而是做这件事分几步,先做什么,后做什么。

  • “面向对象”(Object Oriented)是一种以对象为中心的编程思想,简称 OO。随着计算机技 术的不断提高,计算机被用于解决越来越复杂的问题。一切事物皆对象,通过面向对象的方式, 将现实世界的事物抽象成对象。通过面向对象的方法,更利于用人理解的方式对复杂系统进行分析、设计与编程。同时,面向对象能有效提高编程的效率,通过封装技术,可以像搭积木的 一样快速开发出一个全新的系统。面向对象将对象作为程序的基本单元,将程序和数据封装其 中,以提高软件的重用性、灵活性和扩展性。 使用面向对象编程思想开发系统,在现代开发中会将面向对象贯穿整个过程,一般包括: OOA/OOD/OOP:

    • ① OOA:面向对象分析(Object-Oriented Analysis)

    • ② OOD:面向对象设计(Object-Oriented Design)

    • ③ OOP:面向对象编程(Object-Oriented Programming)

  • 面向过程和面向对象有什么关系呢?

    • 面向过程其实是最为实际的一种思考方式,就算是面 向对象的方法也是含有面向过程的思想。可以说面向过程是一种基础的方法。它考虑的是实际地实现。一般的面向过程是从上往下步步求精。面向对象主要是把事物给对象化,对象包括属性与行为。当程序规模不是很大时,面向过程的方法还会体现出一种优势。因为程序的流程很清楚,按着模块与函数的方法可以很好的组织。但对于复杂而庞大的系统来说,面向过程显得就很无力了。如果采用面向过程方式开发,一步依赖另一步,任何一步都不能变化,变化其中一步则整个软件都会受到影响。 软件工程追求的目标之一就是可维护性,可维护性主要表现在 3 个方面:可理解性、可测试性 和可修改性。面向对象的好处之一就是显著的改善了软件系统的可维护性。 对于编程语言来说,基于 C 语言的编程是面向过程的,C++只能说一半面向过程一半面向对象,java 语言就是一门完全面向对象的编程语言。

面向对象三大特征

  • 封装(Encapsulation)

  • 继承(Inheritance)

  • 多态(Polymorphism)

类的定义

 

对象的创建

  • 类定义之后,就可以使用类这个“模板”来创造“对象”了,一个类是可以创建多个对象。语法格式:new 类名(),例如以下代码:

  • 为了使用对象更加方便,建议使用变量接收一下?例如以下代码:

  •  

对象的使用

  • 创建了对象之后怎么去访问这个对象的属性呢,或者说学生对象现在有了,怎么去访问他的学号、姓名、性别、年龄等信息呢。请看以下代码:

public class Student{
    
    // 学号
    int no = 1001;
    // 姓名
    String name = "张三";
    // 性别
    int sex = 1;
    // 年龄
    int age = 18;
    
    public static vodi main(String[] args){
        
        // 创建学生对象
        Student s = new Student();
        // 访问属性(通过对象名.属性名)
        System.out.println("学号:" + s.no);
        System.out.println("姓名:" + s.name);
        System.out.println("性别:" + s.sex);
        System.out.println("年龄:" + s.age);
        
    }
}
  • 在 java 语言当中,当实例变量没有手动赋值,在创建对象的时候,也就是说在 new 的时候,系统会对实例变量默认赋值, 它们的默认值请参考下表:

  •  

构造方法 Constructor

  • 构造方法是类中特殊的方法,通过调用构造方法来完成对象的创建,以及对象属性的初始化操作。

  • 构造方法怎么定义,请看以下的语法格式:

    • [修饰符列表] 构造方法名(形式参数列表){

      构造方法体;

      }

    • ① 构造方法名和类名一致。

    • ② 构造方法用来创建对象,以及完成属性初始化操作。

    • ③ 构造方法返回值类型不需要写,写上就报错,包括 void 也不能写。

    • ④ 构造方法的返回值类型实际上是当前类的类型。

    • ⑤ 一个类中可以定义多个构造方法,这些构造方法构成方法重载

封装

  • 为了保证内部数据的安全,这个时候就需要进行封装了,封装的第一步就是将应该隐藏的数据隐藏起来,起码在外部是无法随意访问这些数据的,怎么隐藏呢?我们可以使用 java 语 言中的 private 修饰符,private 修饰的数据表示私有的,私有的数据只能在本类当中访问。请看程序:

     

以上程序编译报错了,请看下图:

 

通过以上的测试,手机对象的电压属性确实受到了保护,在外部程序中无法访问了。但从当前情况来看,voltage 属性有点儿太安全了,一个对象的属性无法被外部程序访问,自然这个数据就没有存在的价值了。所以这个时候就需要进入封装的第二步了:对外提供公开的访问入口,让外部程序统一通过这个入口去访问数据,我们可以在这个入口处设立关卡,进行安全 控制,这样对象内部的数据就安全了。 对于“一个”属性来说,我们对外应该提供几个访问入口呢?通常情况下我们访问对象的某个属性,不外乎读取(get)和修改(set),所以对外提供的访问入口应该有两个,这两个 方法通常被称为 set 方法和 get 方法(请注意:set 和 get 方法访问的都是某个具体对象的属性, 不同的对象调用 get 方法获取的属性值不同,所以 set 和 get 方法必须有对象的存在才能调用, 这样的方法定义的时候不能使用 static 关键字修饰,被称为实例方法。实例方法必须使用“引用”的方式调用。请看以下代码:

public class MobilePhone {
    
    //电压:手机正常电压在 3~5V
    private double voltage;
    
    public MobilePhone(){
        
    }
    
    public void setVoltage(double _voltage){
        if(_voltage < 3 || _voltage > 5){
            //当电压低于 3V或者高于 5V时抛出异常,程序则终止
            throw new RuntimeException("电压非法,请爱护手机!");
        }
​
        //程序如果能执行到此处说明以上并没有发生异常,电压值合法
        voltage = _voltage;
    }
    
    public double getVoltage(){
        return voltage;
    }
}
public class MobilePhoneTest {
    public static void main(String[] args) {
        
        MobilePhone phone = new MobilePhone();
        
        phone.setVoltage(3.7);
        System.out.println("手机电压 :" + phone.getVoltage());
        
        phone.setVoltage(100);
        System.out.println("手机电压 :" + phone.getVoltage());
        
    }
}

继承

  • java 中继承的语法格式:

     

继承的相关特性

  • ① B类继承 A类,则称 A类为超类(superclass)、父类、基类,B类则称为子类(subclass)、 派生类、扩展类。

  • ② java 中的继承只支持单继承,不支持多继承,C++中支持多继承,这也是 java 体现简单性的一点。

  • ③ 虽然 java 中不支持多继承,但有的时候会产生间接继承的效果,例如:class C extends B,class B extends A,也就是说,C 直接继承 B,其实 C 还间接继承 A。

  • ④ java 中规定,子类继承父类,除构造方法和被 private 修饰的数据不能继承外,剩 下都可以继承。

  • ⑤ java 中的类没有显示的继承任何类,则默认继承 Object 类,Object 类是 java 语言 提供的根类(老祖宗类),也就是说,一个对象与生俱来就有 Object 类型中所有的特征。

  • ⑥ 继承也存在一些缺点,例如:CreditAccount 类继承 Account 类会导致它们之间的耦合度非常高,Account 类发生改变之后会马上影响到 CreditAccount 类。

简单案例

// 动物类
public class Animal{
    
    // 动物吃的方法
    public void eat(){
        
    }
    
    // 动物移动的方法
    public void move(){
        
    }
    
}
​
// 猫类继承动物类
class Cat extends Animal{
    
    public void eat(){
        System.out.println("猫在吃鱼!");
    }
    
    public void move(){
        System.out.println("猫在跑!");
    }
    
}

方法覆盖的条件及注意事项

  • 当程序具备哪些条件的时候,就能构成方法覆盖呢?

    • ① 方法覆盖发生在具有继承关系的父子类之间,这是首要条件;

    • ② 覆盖之后的方法与原方法具有相同的返回值类型、相同的方法名、相同的形式参数列表;

  • 在使用方法覆盖的时候,需要有哪些注意事项呢?

    • ① 由于覆盖之后的方法与原方法一模一样,建议在开发的时候采用复制粘贴的方式, 不建议手写,因为手写的时候非常容易出错,比如在 Object 类当中有 toString()方法,该方 法中的 S 是大写的,在手写的时候很容易写成小写 tostring(),这个时候你会认为 toString() 方法已经被覆盖了,但由于方法名不一致,导致最终没有覆盖,这样就尴尬了;

    • ② 私有的方法不能被继承,所以不能被覆盖;

    • ③ 构造方法不能被继承,所以也不能被覆盖;

    • ④ 覆盖之后的方法不能比原方法拥有更低的访问权限,可以更高;

    • ⑤ 覆盖之后的方法不能比原方法抛出更多的异常,可以相同或更少;

    • ⑥ 方法覆盖只是和方法有关,和属性无关;

    • ⑦ 静态方法不存在覆盖(不是静态方法不能覆盖,是静态方法覆盖意义不大);

多态基础语法

  • 多态(Polymorphism)属于面向对象三大特征之一,它的前提是封装形成独立体,独立体之间存在继承关系,从而产生多态机制。多态是同一个行为具有多个不同表现形式或形态的能力。现实中,比如我们按下 F1 键这个动作:

    • 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;

    • 如果当前在 Word 下弹出的就是 Word 帮助;

    • 如果当前在 Windows 下弹出的就是 Windows 帮助和支持。

  • 多态就是“同一个行为”发生在“不同的对象上”会产生不同的效果。那么在java 中多态是如何体现的呢?

  • 在 java 中允许这样的两种语法出现,一种是向上转型(Upcasting),一种是向下转型 (Downcasting),向上转型是指子类型转换为父类型,又被称为自动类型转换,向下转型是指父类型转换为子类型,又被称为强制类型转换。请看下图:

     

  • 在 java 语言中有这样的一个规定,无论是向上转型还是向下转型,两种类型之间必须要有继承关系,没有继承关系情况下进行向上转型或向下转型的时候编译器都会报错。

public class Animal {
    public void move(){
        System.out.println("Animal move!");
    }
}
​
​
class Cat extends Animal{
    //方法覆盖
    public void move(){
        System.out.println("走猫步!");
    } 
    //子类特有
    public void catchMouse(){
        System.out.println("抓老鼠!");
    }
}
​
​
class Bird extends Animal{
    //方法覆盖
    public void move(){
        System.out.println("鸟儿在飞翔!");
    }
    //子类特有
    public void sing(){
        System.out.println("鸟儿在歌唱!");
    }
}
public class Test {
    public static void main(String[] args) {
        //创建 Animal 对象
        Animal a = new Animal();
        a.move();
        //创建 Cat 对象
        Cat c = new Cat();
        c.move();
        //创建鸟儿对象
        Bird b = new Bird();
        b.move();
    }
}
  • 以上程序演示的就是多态,多态就是“同一个行为(move)”作用在“不同的对象上”会 有不同的表现结果。java 中之所以有多态机制,是因为 java 允许一个父类型的引用指向一个子 类型的对象。也就是说允许这种写法:Animal a2 = new Bird(),因为 Bird is a Animal 是能够说 通的。其中 Animal a1 = new Cat()或者 Animal a2 = new Bird()都是父类型引用指向了子类型对 象,都属于向上转型(Upcasting),或者叫做自动类型转换。

super 概述

  • super 和 this 可以对比着学习:

  • ① this

    • this 是一个引用,保存内存地址指向自己。

    • this 出现在实例方法中,谁调用这个实例方法,this 就代表谁,this 代表当前正 在执行这个动作的对象。

    • this 不能出现在静态方法中。

    • this 大部分情况下可以省略,在方法中区分实例变量和局部变量的时候不能省略。

    • “this(实际参数列表)”出现在构造方法第一行,通过当前的构造方法去调用 本类当中其它的构造方法。

  • ② super

    • 严格来说,super 其实并不是一个引用,它只是一个关键字,super 代表了当前对象中从父类继承过来的那部分特征。this 指向一个独立的对象,super 并不是指向某个“独立”的对象,假设张大明是父亲,张小明是儿子,有这样一句 话:大家都说张小明的眼睛、鼻子和父亲的很像。那么也就是说儿子继承了父 亲的眼睛和鼻子特征,那么眼睛和鼻子肯定最终还是长在儿子的身上。假设this 指向张小明,那么 super 就代表张小明身上的眼睛和鼻子。换句话说 super 其 实是 this 的一部分。如下图所示:张大明和张小明其实是两个独立的对象,两 个对象内存方面没有联系,super 只是代表张小明对象身上的眼睛和鼻子,因 为这个是从父类中继承过来的,在内存方面使用了 super 关键字进行了标记, 对于下图来说“this.眼睛”和“super.眼睛”都是访问的同一块内存空间。

       

    • super 和 this 都可以使用在实例方法当中。

    • super 不能使用在静态方法当中,因为 super 代表了当前对象上的父类型特征, 静态方法中没有 this,肯定也是不能使用 super 的。

    • super 也有这种用法:“super(实际参数列表);”,这种用法是通过当前的构造 方法调用父类的构造方法。

final 关键字

  • final 表示不可改变的含义

  • 采用 final 修饰的类不能被继承

  • 采用 final 修饰的方法不能被覆盖

  • 采用 final 修饰的变量不能被修改

  • final 修饰的变量必须显示初始化

  • 如果修饰的引用,那么这个引用只能指向一个对象,也就是说这个引用不能再次赋值, 但被指向的对象是可以修改的

  • 构造方法不能被 final 修饰

抽象类

  • 在 java 中采用 abstract 关键字定义的类就是抽象类,采用 abstract 关键字定义的方法就是抽象方法

  • 抽象的方法只需在抽象类中,提供声明,不需要实现

  • 如果一个类中含有抽象方法,那么这个类必须定义成抽象类

  • 如果这个类是抽象的,那么这个类被子类继承,抽象方法必须被重写。如果在子类中不复写该抽象方法,那么必须将此类再次声明为抽象类

  • 抽象的类是不能实例化的,就像现实世界中人其实是抽象的,张三、李四才是具体的

  • 抽象类不能被 final 修饰

  • 抽象方法不能被 final 修饰,因为抽象方法就是被子类实现的

接口

  • 接口我们可以看作是抽象类的一种特殊情况,在接口中只能定义抽象的方法和常量

  • 在 java 中接口采用 interface 声明

  • 接口中的方法默认都是 public abstract 的,不能更改

  • 接口中的变量默认都是 public static final 类型的,不能更改,所以必须显示的初始化

  • 接口不能被实例化,接口中没有构造函数的概念

  • 接口之间可以继承,但接口之间不能实现

  • 接口中的方法只能通过类来实现,通过implements 关键字

  • 如果一个类实现了接口,那么接口中所有的方法必须实现

  • 一类可以实现多个接口

接口和抽象类的区别

  • 接口描述了方法的特征,不给出实现,一方面解决 java 的单继承问题,实现了强大的可接插性

  • 抽象类提供了部分实现,抽象类是不能实例化的,抽象类的存在主要是可以把公共的 代码移植到抽象类中

  • 面向接口编程,而不要面向具体编程(面向抽象编程,而不要面向具体编程)

  • 优先选择接口(因为继承抽象类后,此类将无法再继承,所以会丧失此类的灵活性)

Object 类

  • Object 类是所有 Java 类的根基类

  • 如果在类的声明中未使用 extends 关键字指明其基类,则默认基类为 Object 类

  • toString()

    • 返回该对象的字符串表示。通常 toString 方法会返回一个“以文本方式表示”此对象的字 符串,Object 类的 toString 方法返回一个字符串,该字符串由类名加标记@和此对象哈希码 的无符号十六进制表示组成。

finalize

  • 垃圾回收器(Garbage Collection),也叫 GC,垃圾回收器主要有以下特点:

  • 当对象不再被程序使用时,垃圾回收器将会将其回收

  • 垃圾回收是在后台运行的,我们无法命令垃圾回收器马上回收资源,但是我们可以告 诉他,尽快回收资源(System.gc 和 Runtime.getRuntime().gc())

  • 垃圾回收器在回收某个对象的时候,首先会调用该对象的 finalize 方法

  • GC 主要针对堆内存

  • 单例模式的缺点

==与 equals 方法

  • 等号“==” 等号可以比较基本类型和引用类型,等号比较的是值,特别是比较引用类型,比较的是引用的内存地址。

  • 采用 equals 比较两个对象是否相等(equals底层其实是==,只不过被重写了)。

访问控制权限

 

内部类

  • 在一个类的内部定义的类,称为内部类

  • 内部类主要分类:

    • 实例内部类

    • 局部内部类

    • 静态内部类

  • 实例内部类

    • 创建实例内部类,外部类的实例必须已经创建

    • 实例内部类会持有外部类的引用

    • 实例内部不能定义 static 成员,只能定义实例成员

  •  静态内部类

    • 静态内部类不会持有外部的类的引用,创建时可以不用创建外部类

    • 静态内部类可以访问外部的静态变量,如果访问外部类的成员变量必须通过外部类的实例 访问

  • 局部内部类

    • 局部内部类是在方法中定义的,它只能在当前方法中使用。和局部变量的作用一样,局部内部类和实例内部类一致,不能包含静态成员

  • 匿名内部类

    • 是一种特殊的内部类,该类没有名字

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值