面向对象编程(中)——第二部分

上一篇:面向对象编程(中)——第一部分


5.5 面向对象特征之三: 多态性
1. 多态性的理解

多态性可以理解为一个事物的多种形态。

2. 什么是多态性

对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用);可以直接应用在抽象类和接口上

多态性提高了代码的通用性,常称作接口重用

3. 多态性的使用(虚拟方法调用)

Java引用变量有两个类型:编译时类型运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。简称:编译时,看左边;运行时,看右边

  • 若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism)

  • 多态情况下, “看左边” :看的是父类的引用(父类中不具备子类特有的方法)

    ​ “看右边” :看的是子类的对象(实际运行的是子类重写父类的方法)

例子

// 方法声明的形参类型为父类类型,可以使用子类的对象作为实参调用该方法
public class Test {
    public void method(Person e) {
    	e.getInfo();
    }
    public static void main(Stirng args[]) {
        Test t = new Test();
        Student m = new Student();
        t.method(m); // 子类的对象m传送给父类类型的参数e
    }
}
4. 多态性的使用前提
  • 类的继承关系
  • 方法的重写(如果没有方法的重写没必要使用多态)
5. 注意事项
  1. 对象的多态:在Java中,子类的对象可以替代父类的对象使用

    • 一个变量只能有一种确定的数据类型
    • 一个引用类型变量可能指向(引用)多种不同类型的对象例子

    例子

    Person p = new Student(); 
    Object o = new Person();//Object类型的变量o,指向Person类型的对象 
    o = new Student(); //Object类型的变量o,指向Student类型的对象
    
  2. 子类可看做是特殊的父类,所以父类类型的引用可以指向子类的对象:向上转型(upcasting)

  3. 一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法

    例子

    Student m = new Student();
    m.school = “pku”; //合法,Student类有school成员变量
    Person e = new Student(); 
    e.school = “pku”; //非法,Person类没有school成员变量
    

    属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。

  4. 对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)

6. 虚拟方法调用

概念:子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。

例子

Person e = new Student();
e.getInfo(); //调用Student类的getInfo()方法

编译时e为Person类型,而方法的调用是在运行时确定的,所以调用的是Student类的getInfo()方法。——动态绑定

7. 方法的重载与重写

7.1 二者定义的细节

方法的重载是指在一个类中,具有相同方法名,但是参数列表不相同的方法彼此之间构成重载。

方法的重写是指子类的对象重新实现了父类中定义的同名同参数的方法的方法体。

7.2 从编译和运行的角度看

重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类和子类的,即子类可以重载父类的同名不同参数的方法。 所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法, 这称为“早绑定”或“静态绑定”; 而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动态绑定”。

8. instanceof操作符

用法a instanceof A,判断a是否为类A的对象,返回值是boolean类型,是返回true,否返回false

注意事项

  • 要求a所属的类与类A必须是子类和父类的关系,否则编译错误。
  • 如果a属于类A的子类B,a instanceof A值也为true。
9. 对象类型转换 (Casting )
  • 基本数据类型的Casting

    • 自动类型转换:小的数据类型可以自动转换成大的数据类型

      如long g = 20; double d = 12.0f

      强制类型转换:可以把大的数据类型强制转换(casting)成小的数据类型

      如 float f = (float)12.0; int a = (int)1200L

  • 对Java对象的强制类型转换称为造型

    • 从子类到父类的类型转换可以自动进行(向上转型)
    • 从父类到子类的类型转换必须通过造型实现(向下转型/强制类型转换)
    • 无继承关系的引用类型间的转换是非法的
    • 在造型前可以使用instanceof操作符测试一个对象的类型

例子

public class ConversionTest {
    public static void main(String[] args) {
        Object obj = "Hello";
        String objStr = (String) obj;
    }
}
10. 子类继承父类的注意点
  • 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边

  • 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边

5.6 Object类的使用
1. 相关概念
  • Object类是所有Java类的根父类

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

  • Object类中的功能(属性、方法)具有通用性。

  • Object类中没有定义属性

  • Object类中的方法:equals() / toString() / getClass() /hashCode() / clone() / finalize(),wait() 、 notify()、notifyAll()

  • Object类只声明了一个空参的构造器

2. Object类中的主要结构
方法名称描述
public Object()构造器
protected Object clone() throws CloneNotSupportedException复制当前对象
public boolean equals(Object obj)比较两个对象是否“相等”
protected void finalize() throws Throwable当该对象没有引用指向时,由对象的垃圾回收器调用此方法
public final Class<?> getClass()返回该对象的运行时类
public int hashCode()返回该对象的哈希码值
public final void notify()唤醒在此对象监视器上等待的单个线程
public final void notifyAll()唤醒在此对象监视器上等待的所有线程。
public String toString()返回该对象的字符串表示
public final void wait([参数]) throws InterruptedException线程等待
  • clone()方法

    此方法执行的是该对象的“浅表复制”,而不“深层复制”操作,即如果对象中有引用类型的字段,复制的是字段的引用,而非引用的对象,指向的是同一个对象。

  • finalize()

    垃圾回收机制关键点

    • 垃圾回收机制只回收JVM堆内存里的对象空间,对其他物理连接,比如数据库连接、输入流输出流、Socket连接无能为力

    • 现在的JVM有多种垃圾回收实现算法,表现各异。

    • 垃圾回收发生具有不可预知性,程序无法精确控制垃圾回收机制执行。

    • 可以将对象的引用变量设置为null,暗示垃圾回收机制可以回收该对象。

    • 可以通过System.gc()或者Runtime.getRuntime().gc()来通知系统进行垃圾回收,会有
      一些效果,但是系统是否进行垃圾回收依然不确定。

    • 垃圾回收机制回收任何对象之前,总会先调用它的finalize方法(如果覆盖该方法,让一
      个新的引用变量重新引用该对象,则会重新激活对象)。

    • 永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用。

3. == 和 equals() 区别

== :运算符

  • 可以使用在基本数据类型变量和引用数据类型变量中

  • 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)

    如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体

  • 用“==”进行比较时,符号两边的数据类型必须兼容(可自动转换的基本数据类型除外),否则编译出错

equals():是一个方法,而非运算符

  • 只能适用于引用数据类型,格式:obj1.equals(obj2)

  • Object类中equals()的定义:

    public boolean equals(Object obj) {
    	return (this == obj);
    }
    

    Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体

  • String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。

  • 通常情况下,自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,就需要对Object类中的equals()进行重写,

  • 重写的原则:比较两个对象的实体内容是否相同

    • 对称性:如果x.equals(y)返回是“true” ,那么y.equals(x)也应该返回是 “true”

    • 自反性:x.equals(x)必须返回是“true”

    • 传递性:如果x.equals(y)返回是“true” ,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”

    • 一致性:如果x.equals(y)返回是“true” ,只要x和y内容一直不变,不管重复x.equals(y)多少次,返回都是“true”。

    • 任何情况下,x.equals(null),永远返回是“false” ;

      x.equals(和x不同类型的对象)永远返回是“false”。

4. toString() 方法
  • toString()方法在Object类中定义,其返回值是String类型,返回类名和它的引用地址。

  • 当输出一个对象的引用时,实际上就是调用当前对象的toString()

    Date now = new Date();
    System.out.println(now); 
    // 相当于
    System.out.println(now.toString());
    
  • Object类中toString()的定义:

    public String toString() {
    	return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    

    Object类中定义的toString()返回的是该对象的类名以及虚拟的内存地址

  • String、Date、File、包装类等都重写了Object类中的toString()方法,在调用对象的toString()时,返回的是"实体内容"信息

  • 自定义类可以重写toString()方法,当调用此方法时,返回对象的"实体内容"

  • 基本类型数据转换为String类型时,调用了对应包装类的toString()方法

5.7 Java中的JUnit单元测试的使用
1. 在eclipse中:

步骤

  1. 选中当前工程 - 右键选择:build path - add libraries - JUnit 4 - 下一步

  2. 创建Java类,进行单元测试。此时的Java类要求:① 此类是public的 ②此类提供公共的无参的构造器

  3. 此类中声明单元测试方法。此时的单元测试方法:方法的权限是public,没有返回值,没有形参

  4. 此单元测试方法上需要声明注解:@Test,并在单元测试类中导入:import org.junit.Test;

  5. 声明好单元测试方法以后,就可以在方法体内测试相关的代码。

  6. 写完代码以后,左键双击单元测试方法名,右键:run as - JUnit Test

说明

  1. 如果执行结果没有任何异常:绿条

  2. 如果执行结果出现异常:红条

5.8 包装类的使用

java提供了8种基本数据类型对应的包装类(封装类),使得基本数据类型的变量具有类的特征

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter

其中Byte、Short、Integer、Long、Float、Double的父类为Number类

1. 基本数据类型 —> 包装类
  • 通过包装类的构造器

    // 数值型参数: 
    int i = 500; 
    Integer t = new Integer(i);
    // 字符串参数
    Float f = new Float("3.14"); 
    // 如果为字符串参数需要是数值,下面的这种会报异常:NumberFormatException
    Long l = new Long(“asdf”);
    // boolean类型的包装类有进行优化,当字符串转小写后与"true"相等即为true,否则为false
    Boolean b1 = new Boolean(true);
    Boolean b2 = new Boolean("TrUe");
    System.out.println(b2); // true
    Boolean b3 = new Boolean("true123");
    System.out.println(b3); // false
    
  • JDK1.5之后,使用自动装箱:类型必须匹配

    int num = 10;
    Integer integer = num; // 自动装箱
    
2. 包装类 —> 基本数据类型
  • 调用包装类Xxx的xxxValue()方法

    Integer integer = new Integer(12);
    int num = integer.intValue();
    System.out.println(num + 1); // 13
    
    Float f1 = new Float(12.3);
    float f2 = f1.floatValue();
    System.out.println(f2 + 1); // 13.3
    
  • JDK1.5之后,使用自动拆箱:类型必须匹配

    Integer integer = new Integer(12);
    int num = integer;//自动拆箱
    
3. 基本数据类型、包装类 —> String类型
  • 使用字符串连接

    int num = 10;
    String str = num + "";
    
  • 调用String重载的valueOf(xxx)

    float f = 12.3f;
    String str1 = String.valueOf(f); // "12.3"
    System.out.println(str1); // "12.3"
    
    Double d = new Double(12.4);
    String str2 = String.valueOf(d);
    System.out.println(str2); // "12.4"
    
  • 通过toString()方法

    Double d = 3.14;
    String str1 = d.toString();
    System.out.println(str1); // "3.14"
    
    String str2 = Double.toString(1.11);
    System.out.println(str2); // "1.11"
    
4. String类型 —> 基本数据类型、包装类
  • 通过包装类的构造器实现

    int i = new Integer("12");
    
  • 调用包装类的parseXxx(xxx)

    Float f = Float.parseFloat("12.1");
    
5. 补充

转换相同类型

// 在编译时,Integer类型会转换为double类型
Object o1 = true ? new Integer(1) : new Double(2.0);
System.out.println(o1); // 1.0

Integer类型的缓存:IntegerCache

在Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],其保存了从-128127范围的整数。如果使用自动装箱的方式,给Integer赋值的范围在-128127范围内时,可以直接使用数组中的元素,不用再去new了,其目的是为了提高效率。

Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j); // false

Integer m = 1;
Integer n = 1;
System.out.println(m == n); // true

// 相当于new了一个Integer对象
Integer x = 128; 
Integer y = 128;
System.out.println(x == y); // false

下一篇:面向对象编程(下)——第一部分

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 本章主要针对初学者,简要介绍了c/c++的基本语法和常见的编译错误。首先,介绍了程序的基本结构和常用的数据类型。c语言的基本语句包括赋值语句、条件语句和循环语句等,这些语句都可以组成程序的逻辑结构。接下来,介绍了函数的定义和调用,以及参数传递的方式。对于c++,还介绍了一些面向对象的概念,例如类、对象、成员函数等。同时,也提到了头文件和命名空间的使用方法。 在编程过程,常常会出现各种编译错误,例如语法错误、类型不匹配、语义错误等,需要学会如何查看和解决这些错误。此外,还介绍了调试工具和各种常用的运算符和表达式,这些都是初学者必须掌握的基础知识。 总的来说,本章是关于c/c++快速入门的一篇简介性文章。虽然只是涉及到了基础的语法和知识点,但对于初学者而言是一个很好的起点。在学习过程需要不断实践,积累经验,并不断深入了解更高级的编程技术和工具。 ### 回答2: C/C++是一种广泛使用的编程语言,它具有高效、灵活、可移植等特点,在各个领域得到广泛应用。C语言是C++语言的基础,在学习C++之前,需要先掌握C语言的基础知识。 本文介绍的是C/C++教程的第二章——快速入门C/C++。在这一章节,我们将介绍C语言的基本语法、变量、运算符和流程控制语句等基础知识。以下是C语言的一些基本知识点。 C语言的基本语法: C语言程序由多个函数组成,其一个函数必须命名为main(),程序从该函数开始执行。C程序的语句以分号结束,注释使用“//”表示单行注释,“/* */”表示多行注释。 变量和数据类型: C语言变量的定义格式为“数据类型 变量名”;数据类型包括基本类型和用户自定义类型。C语言的基本类型有int类型、char类型、float类型和double类型等。其,int类型表示整型,char类型表示字符型,float类型和double类型表示浮点型。 运算符: C语言的运算符包括算术运算符、关系运算符、逻辑运算符等。例如,“+”表示加法运算符,“>=”表示大于等于运算符,“&&”表示逻辑与运算符。 流程控制语句: C语言的流程控制语句包括if语句、switch语句、while语句、do-while语句和for语句等。这些语句可以根据条件执行相应的语句块。 总之,本章节的快速入门C/C++,具有基本语法、变量、运算符和流程控制语句等基础知识。初学者可以通过这些基础知识,轻松入门C/C++,为后续学习打下基础。同时,要注意编写代码的规范和逻辑性,才能更好的理解和使用C/C++语言。 ### 回答3: C语言是一门广泛使用的编程语言,具有高效、灵活、稳定等特点,被广泛应用于嵌入式系统、操作系统、驱动程序、多媒体应用等领域。学习C语言是程序员的必备技能之一。 第二章的快速入门C/C++教程,主要介绍了C/C++语言的基础知识,重点是程序的结构和输入输出。其程序结构包括函数、语句、变量、表达式等,而输入输出则包括scanf、printf、getchar和putchar等函数。 # 程序结构 程序结构是指程序的基本构成单元,包括函数、语句、变量、表达式等。C语言的程序结构主要包含以下几个方面。 ## 函数 C语言,函数是程序的基本组成单元。一个C程序可以由一个或多个函数组成,每个函数可以完成一个任务。函数的格式如下: ```c 返回类型 函数名(参数1, 参数2, ...){ // 函数体 return 返回值; } ``` 其,返回类型指函数执行后的返回值类型;函数名是由程序员定义的,用于调用函数时识别函数;参数列表是函数的输入参数,可以有多个参数,每个参数由类型和变量名组成;函数体是函数要执行的代码块;return语句可以返回函数的执行结果。 ## 语句 语句是完成特定功能的一组指令。C语言的语句包括赋值语句、条件语句、循环语句等。C语言通常使用花括号来表示语句块。例如,下面是一个if语句的例子。 ```c if(条件){ // if语句块 }else{ // else语句块 } ``` 如果条件为真,则执行if语句块的代码;否则执行else语句块的代码。 ## 变量 变量是用于存储数据的一种容器。在C语言,一个变量包括变量名、类型和值。变量名由程序员定义,用于识别变量;类型指变量的数据类型,如整型、字符型、实型等;值是存储在变量的数据。变量的定义格式如下。 ```c 数据类型 变量名 = 值; ``` 例如,下面是一个整型变量的定义。 ```c int num = 10; ``` ## 表达式 表达式是由变量、运算符和常量组成的一个具有返回值的语句。C语言的运算符分为算术运算符、关系运算符、逻辑运算符等,例如加号、减号、乘号、除号等。下面是一个简单的表达式。 ```c a = 5 + 6 * 3 / 2 - 1; ``` 这个表达式将计算5加6乘3除以2减1的值,并将结果赋给a变量。 # 输入输出 输入输出是程序非常重要的部分,可以让程序与用户进行交互。C语言有多种输入输出函数,其一些最常用的是scanf、printf、getchar和putchar函数。 ## scanf函数 scanf函数用于从标准输入读取格式化数据,并将读取的数据存储到变量。它的格式如下。 ```c scanf("格式控制字符串", 变量列表); ``` 其,格式控制字符串指示scanf函数需要读取的数据类型和格式,变量列表指向要读取的变量。下面是一个scanf函数的例子。 ```c int num; scanf("%d", &num); ``` 这个代码段将从标准输入读取一个整数,并将其存储到num变量。 ## printf函数 printf函数用于将格式化数据输出到标准输出。它的格式如下。 ```c printf("格式控制字符串", 参数列表); ``` 其,格式控制字符串指示printf函数需要输出的数据类型和格式,参数列表包含要输出的变量和常量。下面是一个printf函数的例子。 ```c int num = 5; printf("num的值是%d\n", num); ``` 这个代码段将输出“num的值是5”。 ## getchar和putchar函数 getchar函数用于从标准输入读取一个字符,putchar函数用于将一个字符输出到标准输出。它们的用法非常简单,例如下面的代码将读取一个字符并将其转换成大写字母后输出。 ```c char c = getchar(); putchar(toupper(c)); ``` 以上就是第二章的快速入门C/C++教程的主要内容,包括程序结构和输入输出方面的基础知识。熟练掌握这些内容,对于学习C语言来说是非常重要的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT程

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值