零基础学java(6)——面向对象的基本特征

第六章 面向对象的基本特征

面向对象的基本特征:

1、封装

2、继承

3、多态

6.1 封装

1、好处:

(1)隐藏实现细节,方便使用者使用

(2)安全,可以控制可见范围

2、如何实现封装?

通过权限修饰符

面试题:请按照可见范围从小到大(从大到小)列出权限修饰符?

修饰符 本类 本包 其他包的子类 任意位置
private × × ×
缺省 × ×
protected ×
public

权限修饰符可以修饰什么?

类(类、接口等)、属性、方法、构造器、内部类

类(外部类):public和缺省

属性:4种

方法:4种

构造器:4种

内部类:4种

3、通常属性的封装是什么样的?

当然属性的权限修饰符可以是private、缺省、protected、public。但是我们大多数时候,见到的都是private,然后给它们配上get/set方法。

示例代码:标准Javabean的写法

public class Student{
    
    
    //属性私有化
    private String name;
    private int age;
    private boolean marry;
    
    //公共的get/set
    public void setName(String n){
    
    
        name = n;//这里因为还没有学习this等,可能还会优化
    }
    public String getName(){
    
    
        return name;
    }
    public void setAge(int a){
    
    
        age = a;
    }
    public int getAge(){
    
    
        return age;
    }
    public void setMarry(boolean m){
    
    
        marry = m;
    }
    public boolean isMarry(){
    
    //boolean类型的属性的get方法,习惯使用把get换成is
        return marry;
    }
}

6.2 构造器

1、构造器的作用:
(1)和new一起使用创建对象

//调用无参构造创建对象
类名 对象名 = new 类名();

//调用有参构造创建对象
类名 对象名 = new 类名(实参列表);

(2)可以在创建对象的同时为属性赋值

public class Circle{
    
    
    private double radius;
    
    public Circle(){
    
    
        
    }
    public Circle(double r){
    
    
        radius = r;//为radius赋值
    }
}

2、声明构造器的语法格式:

【修饰符】 class 类名{
    
    
    【修饰符】 类名(){
    
    //无参构造
        
    }
    【修饰符】 类名(形参列表){
    
    //有参构造
        
    }
}

3、构造器的特点:

(1)所有的类都有构造器

(2)如果一个类没有显式/明确的声明一个构造器,那么编译器将会自动添加一个默认的无参构造

(3)如果一个类显式/明确的声明了构造器,那么编译器将不再自动添加默认的无参构造,如果需要,那么就需要手动添加

(4)构造器的名称必须与类名相同

(5)构造器没有返回值类型

(6)构造器可以重载

示例代码:

public class Circle{
    
    
    private double radius;
    
    public Circle(){
    
    
        
    }
    public Circle(double r){
    
    
        radius = r;//为radius赋值
    }
}

6.3 关键字this

1、this关键字:

意思:当前对象

(1)如果出现在构造器中:表示正在创建的对象

(2)如果出现在成员方法中:表示正在调用这个方法的对象

2、this的用法:

(1)this.属性

当局部变量与成员变量同名时,那么可以在成员变量的而前面加“this.”用于区别

(2)this.方法

调用当前对象的成员方法,完全可以省略“this.”

(3)this()或this(实参列表)

this()表示调用本类的无参构造

this(实参列表)表示调用本类的有参构造

this()或this(实参列表)要么没有,要么必须出现在构造器的首行

示例代码:

public class Student{
    
    
    private String name;
    private int score;
    
    public Student(){
    
    
        
    }
    public Student(String name){
    
    
        this.name = name;
    }
    public Student(String name, int score){
    
    
        this(name);
    }
    public void setName(String name){
    
    
        this.name = name;
    }
    public String getName(){
    
    
        return name;
    }
    public void setScore(int score){
    
    
        this.score = score;
    }
    public int getScore(){
    
    
        return score;
    }
}

3、成员变量与局部变量的区别?

这里只讨论实例变量(关于类变量见static部分)

(1)声明的位置不同

成员变量:类中方法外

局部变量:方法中或代码中

​ ①方法的形参列表

​ ②方法体中局部变量

​ ③代码块中的局部变量

(2)运行时在内存中的存储位置不同

成员变量:堆

局部变量:栈

基本数据类型的变量在栈中,引用数据类型的变量在堆中:不准确

(3)修饰符

成员变量:有很多修饰符,例如:权限修饰符

局部变量:不能加权限修饰符,唯一的能加的是final

(4)初始化

成员变量:有默认值

局部变量:没有默认值,必须手动初始化

(5)生命周期

成员变量:随着对象的创建而创建,随着对象被回收而消亡,即与对象同生共死。每一个对象都是独立的。

局部变量:方法调用时才分配,方法运行结束就没有了。每一次方法调用,都是独立的

6.4 包

1、包的作用:

(1)可以避免类重名

有了包之后,类的全名称就变为:包.类名

(2)分类组织管理众多的类

例如:java.lang包,java.util包,java.io包…

(3)可以控制某些类型或成员的可见范围

如果某个类型或者成员的权限修饰缺省的话,那么就仅限于本包使用

2、声明包的语法格式:

package 包名;

注意:

(1)必须在源文件的代码首行

(2)一个源文件只能有一个

3、包的命名规范和习惯:
(1)所有单词都小写,每一个单词之间使用.分割
(2)习惯用公司的域名倒置

例如:com.atguigu.xxx;

建议大家取包名时不要使用“java.xx"包

4、使用其他包的类:

前提:被使用的类或成员的权限修饰符是>缺省的

(1)使用类型的全名称

例如:java.util.Scanner input = new java.util.Scanner(System.in);

(2)使用import 语句之后,代码中使用简名称

5、import语句

import.类名;
import.*;

注意:当使用两个不同包的同名类时,例如:java.util.Date和java.sql.Date。

一个使用全名称,一个使用简名称

示例代码:

package com.atguigu.test;

import java.util.Scanner;

public class Test{
    
    
    public static void main(String[] args){
    
    
        Scanner input = new Scanner(System.in);
    }
}

6.5 eclipse的使用

1、eclipse管理项目和代码的结构

workspace --> project --> 包–>类…

一个工作空间可以有多个项目。

2、快捷键

常规快捷键:

Ctrl + S:保存

Ctrl + C:复制

Ctrl + V:粘贴

Ctrl + X:剪切

Ctrl + Y:反撤销

Ctrl + Z:撤销

Ctrl + A:全选

eclipse中默认的快捷键:

Ctrl + 1:快速修复

Alt + /:代码提示

Alt + ?: Alt + Shift + / 方法的形参列表提示

Ctrl + D:删除选中行

Ctrl + Alt + ↓:向下复制行

Ctrl + Alt + ↑:向上复制行

Alt + ↓:与下面的行交换位置

Alt + ↑:与下面的行交换位置

Ctrl + Shift + F:快速格式

Ctrl + /:单行注释,再按一次取消

Ctrl + Shift + /:多行注释

Ctrl + Shift +\:取消多行注释

Shift + 回车:在光标下一行插入新航开始编辑

Ctrl + Shift + 回车:在光标上一行插入新航开始编辑

Alt + Shift + A:多行编辑 再按一次退出多行编辑模式

Alt + Shift + S:弹出自动生成代码的菜单选择,包括自动生成构造器、get/set、equals…

Ctrl + Shift + O:快速导包

Ctrl + Shift + T:打开某个类的源文件

Ctrl + O:打开某个类型的摘要outline

3、快速开发的代码模板

代码模板 + Alt + /

(1)main

public static void main(String[] args){

}

(2)sysout

System.out.println();

(3)for

for(int i=0; i<数组名.lenght; i++){

}

其他详细使用见《JavaSE_柴林燕_相关工具.docx》

6.6 面向对象的基本特征之二:继承

1、为什么要继承?继承的好处?(理解)

(1)代码的复用

(2)代码的扩展

2、如何实现继承?

语法格式:

【修饰符】 class 子类  extends 父类{
    
    
    
}

3、继承的特点

(1)子类会继承父类的所有特征(属性、方法)

但是,私有的在子类中是不能直接使用的

(2)子类不会继承父类的构造器

因为,父类的构造器是用于创建父类的对象的

(3)子类的构造器中又必须去调用父类的构造器

在创建子类对象的同时,为从父类继承的属性进行初始化用,可以借助父类的构造器中的代码为属性赋值。

(4)Java只支持单继承:一个子类只能有一个“直接”父类

(5)Java又支持多层继承:父类还可以有父类,特征会代代相传

(6)一个父类可以同时拥有很多个子类

6.7 关键字super

super关键字:引用父类的,找父类的xx

用法:

(1)super.属性

当子类声明了和父类同名的成员变量时,那么如果要表示某个成员变量是父类的,那么可以加“super.”

(2)super.方法

当子类重写了父类的方法,又需要在子类中调用父类被重写的方法,可以使用"super."

(3)super()或super(实参列表)

super():表示调用父类的无参构造

super(实参列表):表示调用父类的有参构造

注意:

(1)如果要写super()或super(实参列表),必须写在子类构造器的首行

(2)如果子类的构造器中没有写:super()或super(实参列表),那么默认会有 super()

(3)如果父类没有无参构造,那么在子类的构造器的首行“必须”写super(实参列表)

6.8 方法的重写

1、方法的重写(Override)

当子类继承了父类的方法时,又觉得父类的方法体的实现不适合于子类,那么子类可以选择进行重写。

2、方法的重写的要求

(1)方法名:必须相同

(2)形参列表:必须相同

(3)修饰符

​ 权限修饰符: >=

(4)返回值类型

​ 如果是基本数据类型和void:必须相同

​ 如果是引用数据类型:<=

​ 在Java中我们认为,在概念范围上:子类 <父类

3、重载(Overload)与重写(Override)的区别

​ 重载(Overload):在同一个类中,方法名相同,形参列表不同,和返回值类型无关的两个或多个方法。

​ 重写(Override):在父子类之间。对方法签名的要求见上面。

特殊的重载:

public class TestOverload {
    
    
	public static void main(String[] args) {
    
    
		B b = new B();
		//b对象可以调用几个a方法
		b.a();
		b.a("");//从b对象同时拥有两个方法名相同,形参不同的角度来说,算是重载
	}
}
class A{
    
    
	public void a(){
    
    
		//...
	}
}
class B extends A{
    
    
	public void a(String str){
    
    
		
	}
}

6.9 非静态代码块

1、语法格式

【修饰符】 class 类名{
    
    
    {
    
    
        非静态代码块
    }
}

2、作用

目的:在创建的过程中,为对象属性赋值,协助完成实例初始化的过程

3、什么时候执行?

(1)每次创建对象时都会执行

(2)优先于构造器执行

6.10 实例初始化过程

1、概念描述

  • 实例初始化过程:实例对象创建的过程

  • 实例初始化方法:实例对象创建时要执行的方法

  • 实例初始化方法的由来:它是有编译器编译生成的

  • 实例初始化方法的形式:()或(形参列表)

  • 实例初始化方法的构成:

    ①属性的显式赋值代码

    ②非静态代码块的代码

    ③构造器的代码

    其中

    ①和②按顺序执行,从上往下

    ③在①和②的后面

因此一个类有几个构造器,就有几个实例初始化方法。

2、单个类实例初始化方法

示例代码:

class Demo{
    
    
	{
    
    
		System.out.println("非静态代码块1");
	}
	
	private String str = assign();//调用方法,来为str进行显式赋值
	
	public Demo(){
    
    
		System.out.println("无参构造");
	}
	public Demo(String str){
    
    
		this.str = str;
		System.out.println("有参构造");
	}
	
	{
    
    
		System.out.println("非静态代码块2");
	}
	
	public String assign(){
    
    
		System.out.println("assign方法");
		return "hello";
	}
}

图解:

1558960549421

3、父子类的实例初始化

注意:

(1)原先super()和super(实参列表)说是调用父类的构造器,现在就要纠正为调用父类的实例初始化方法了

(2)原先super()和super(实参列表)说是必须在子类构造器的首行,现在要纠正为必须在子类实例初始化方法的首行

结论:

(1)执行顺序是先父类实例初始化方法,再子类实例初始化方法

(2)如果子类重写了方法,通过子类对象调用,一定是执行重写过的方法

示例代码:

class Ba{
    
    
	private String str = assign();
	{
    
    
		System.out.println("(1)父类的非静态代码块");
	}
	public Ba(){
    
    
		System.out.println("(2)父类的无参构造");
	}
	public String assign(){
    
    
		System.out.println("(3)父类的assign()");
		return "ba";
	}
}
class Er extends Ba{
    
    
	private String str = assign();
	{
    
    
		System.out.println("(4)子类的非静态代码块");
	}
	public Er(){
    
    
		//super()  ==>调用父类的实例初始化方法,而且它在子类实例初始化方法的首行
		System.out.println("(5)子类的无参构造");
	}
	
	public String assign(){
    
    
		System.out.println("(6)子类的assign()");
		return "er";
	}
}
class Test{
    
    
    public static void main(String[] args){
    
    
        new Er();//612645
    }
}

图解:

1558961723911

6.11 面向对象的基本特征之三:多态

1、多态:

语法格式:

父类 引用/变量 = 子类的对象;

2、前提:

(1)继承

(2)方法的重写

(3)多态引用

3、现象:

​ 编译时看左边/“父类”,运行时看右边/“子类”。

​ 编译时,因为按父类编译,那么只能父类有的方法,子类扩展的方法是无法调用的;

​ 执行时一定是运行子类重写的过的方法体。

示例代码:

class Person{
    
    
	public void eat(){
    
    
		System.out.println("吃饭");
	}
	public void walk(){
    
    
		System.out.println("走路");
	}
}
class Woman extends Person{
    
    
	public void eat(){
    
    
		System.out.println("细嚼慢咽的吃饭");
	}
	public void walk(){
    
    
		System.out.println("婀娜多姿走路");
	}
	public void shop(){
    
    
		System.out.println("买买买...");
	}
}
class Man extends Person{
    
    
	public void eat(){
    
    
		System.out.println("狼吞虎咽的吃饭");
	}
	public void walk(){
    
    
		System.out.println("大摇大摆的走路");
	}
	public void smoke(){
    
    
		System.out.println("吞云吐雾");
	}
}
class Test{
    
    
    public static void main(String[] args){
    
    
        Person p = new Woman();//多态引用
        p.eat();//执行子类重写
        p.walk();//执行子类重写
        //p.shop();//无法调用
    }
}

4、应用:

(1)多态参数:形参是父类,实参是子类对象

(2)多态数组:数组元素类型是父类,元素存储的是子类对象

示例代码:多态参数

class Test{
    
    
    public static void main(String[] args){
    
    
        test(new Woman());//实参是子类对象
        test(new Man());//实参是子类对象
    }
    public static void test(Person p){
    
    //形参是父类类型
        p.eat();
        p.walk();
    }
}

示例代码:多态数组

class Test{
    
    
    public static void main(String[] args){
    
    
        Person[] arr = new Person[2];//多态数组
        arr[0] = new Woman();
        arr[1] = new Man();
        
        for(int i=0; i<arr.length; i++){
    
    
            all[i].eat();
            all[i].walk();
        }
    }
}

5、向上转型与向下转型:父子类之间的转换

(1)向上转型:自动类型转换

​ 当把子类的对象赋值给父类的变量时(即多态引用时),在编译时,这个对象就向上转型为父类。此时就看不见子类“特有、扩展”的方法。

(2)向下转型:强制转换。有风险,可能会报ClassCastException异常。

​ 当需要把父类的变量赋值给一个子类的变量时,就需要向下转型。

要想转型成功,必须保证该变量中保存的对象的运行时类型是<=强转的类型

示例代码:

class Person{
    
    
	//方法代码省略...
}
class Woman extends Person{
    
    
    //方法代码省略...
}
class ChineseWoman extends Woman{
    
    
	//方法代码省略...
}
 public class Test{
    
    
     public static void main(String[] args){
    
    
		//向上转型
		Person p1 = new Woman();
		//向下转型
		Woman m = (Woman)p1; 
		//p1变量中实际存储的对象就是Woman类型,和强转的Woman类型一样

		//向上转型
		Person p2 = new ChineseWoman();
		//向下转型
		Woman w2 = (Woman) p2; 
		//p2变量中实际存储的对象是ChineseWoman类型,强制的类型是Woman,ChineseWoman<Woman类型     
     }
 }

6、instanceof

表达式语法格式:

对象/变量  instanceof  类型

运算结果:true 或 false

作用:

用来判断这个对象是否属于这个类型,或者说,是否是这个类型的对象或这个类型子类的对象

示例代码:

class Person{
    
    
	//方法代码省略...
}
class Woman extends Person{
    
    
    //方法代码省略...
}
class ChineseWoman extends Woman{
    
    
	//方法代码省略...
}
 public class Test{
    
    
     public static void main(String[] args){
    
    
         Person p = new Person();
         Woman w = new Woman();
         ChineseWoman c = new ChineseWoman();
         
         if(p instanceof Woman){
    
    //false
             
         }
         if(w instanceof Woman){
    
    //true
             
         }
         if(c instanceof Woman){
    
    //true
             
         }
     }
 }

おすすめ

転載: blog.csdn.net/weixin_43912367/article/details/117434359