04_面向对象(基础)

四、面向对象(基础)

4.0 Java学习三条主线

  1. Java类及类的成员:属性方法构造器; 代码块、内部类
  2. 面向对象的三大特征:封装继承多态
  3. 其它关键字:this、super、static、final、abstract、interface、package、import

4.1 面向过程(POP)与面向对象(OOP)

  • 面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做
  • 面向对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做

4.2 Java语言基本元素:类和对象

  • 是对一类事物的描述,是抽象的、概念上的定义
  • 对象 是实际存在的该类事物的每个个体,因而也称为实例(instance)

类的成员1. 属性 = 成员变量 = field = 域、字段

2.方法= 成员方法 = 函数 = method

4.2.1 类和对象的使用

  1. 创建类、设计类的成员
class Person{
	//属性
	String name;
	int age=1;
	boolean isMale;
    
    public void eat(){
        吃饭;
    }
    
}
  1. 创建类的对象

  2. 通过 “对象.属性” 或 “对象.方法” 调用对象的结构

//创建类的对象
Person p1= new Person();
//调用属性
p1.name="Tom";
pi.isMale="True";
System.out.println("p1.name");

Person p2= new Person();
System.out.println("p2.name");//null
System.out.println("p2.isMale");//false

//把 p1变量 保存的 对象地址值 赋给 p3,导致p1和p3指向了堆空间中同一实体
Person p3 = p1;
System.out.println("p3.name");//Tom
p3.age=10;
System.out.println("p1.age");//10

4.2.2 类的成员之一:属性

属性(成员变量) 与 局部变量

  1. 相同点

    1.1 定义变量的格式: 数据类型 变量名 = 变量值

    1.2 先声明,后使用

    1.3 变量都有其作用域

  2. 不同点

    2.1 声明位置不同

    ​ 属性:直接定义在类的{}中

    ​ 局部变量:声明在 方法内方法形参代码块内构造器形参构造器内部 的变量

    2.2 在内存中加载的位置:

    ​ 属性:加载到 堆空间 中(非static)

    ​ 局部变量:加载到 栈空间

    2.3 权限修饰符的不同

    ​ 属性:可以在声明属性时,制定其权限、使用权限修饰符。

    ​ 常用权限修饰符:privatepublic缺省protected

    2.4 生命周期不同

    2.5 默认初始化值情况

    ​ 属性:类的属性,根据其类型,都有默认初始化值。

​ 整型(byte、short、int、long):0

​ 浮点型(float、double):0.0

​ 字符型(char):0

​ 布尔型(boolean):false

​ 引用数据类型(类、数组、接口):null

​ 局部变量:没有默认初始化值—在调用局部变量时,一定要显式赋值。

​ 特别的,形参在调用时赋值即可。

4.2.3 类的成员之二:方法

方法:描述类应该具有的功能。

方法声明

​ 权限修饰符 返回值类型 方法名(形参列表){

​ 方法体

​ }

注:由 static、final、abstract来修饰的方法,后面再讲。

return关键字使用:

  1. 使用范围:在方法体中。

  2. 作用:①结束方法

    ​ ②有返回值的方法,使用"return 数据"返回数据

4.3 JVM内存结构

《JVM规范》

编译完源程序后,生成一个或多个字节码文件。

我们使用JVM中的类的加载器和解释器对生成的字节码文件进行解释运行。意味着,需要将字节码文件对应的类加载到内存中,涉及到内存解析。

Java中内存结构划分为:虚拟机栈方法区程序计数器本地方法栈

  • 虚拟机栈:以 栈帧 为基本单位,有入栈和出栈操作;每个栈帧入栈操作对应一个方法的执行;方法内的 局部变量 存放在 栈帧 中。

  • :我们将 new出来的结构(数组,对象)加载在 堆空间 中:

    • 数组,数组的元素在堆中
    • 对象的成员变量在堆中
    • 补充:对象的属性(非static)加载在 堆空间 中。
  • 方法区:加载的类的模板信息、常量池、静态域。

4.4 变量分类

4.4.1 按数据类型

引用数据类型:类、数组、接口、枚举、注解、记录。

4.4.2 按在类中声明的位置

注:引用类型的变量,只可能存储两类值: null 或 地址值(含变量的类型)

4.5 匿名对象

  1. 理解:

    ​ 我们创建的对象,没有显式的赋给一个变量名,即为匿名对象。

  2. 特征:

    ​ 匿名对象只能调用一次。(匿名对象一经使用,就被回收)

  3. 使用:

    ​ 代码块 line:18-20

public class InstanceTest {
	public static void main(String[] args){
		Phone p = new Phone();
		System.out.println(p);
		
		p.sendEmail();
        p.playGame();
		
		//匿名对象的使用
		new Phone().sendEmail();
        new Phone().playGame();
        
        new Phone().price=1999;
        new Phone().showPrice();//0.0
        
        //****************************
        PhoneMall mall = new PhoneMall();
        //匿名对象的使用
        mall.show(new Phone());
        //匿名对象(作为实参)赋给形参,相当于赋给一个有名字的对象
	}
}

class PhoneMall{
    public void show(Phone phone){
        phone.sendEmail();
        phone.playGame():
    }
}

class Phone{
	double price;//价格
		
	public void sendEmail(){
		
	}	
    public void playGame(){
		System.out.println("打游戏");
	}
    public void showPrice(){
        System.out.println("手机价格为"+price);
    }
}

4.6 再谈方法

4.6.1 方法的重载(Overload)

  1. 定义:

​ 1. 同一个类中,允许存在 同名方法 ,但 参数个数参数类型 不同。

​ 2. 与 返回值类型 无关,只看参数列表,且参数列表(参数个数参数类型)必须不同。

​ 3. 调用时,根据 方法参数列表的不同 来区别。

两同一不同”:- 同一个类,相同方法名

​ - 参数列表不同:参数个数不同,参数类型不同

  1. 举例:

    ​ Arrays类中重载的sort()/binarySearch()

  2. 判断是否是重载:

    ​ 跟方法的 权限修饰符返回值类型形参变量名方法体 都没有关系!

  3. 在通过对象调用方法时,如何确定一个指定的方法:

    ​ 方法名 ----> 参数列表

4.6.2 可变形参的方法

Varargs(variable number of arguments):可变个数的形参,允许直接定义能和多个实参相匹配的形参。

  1. JDK 5.0 新增的内容

  2. 具体使用:

    ​ 2.1 可变个数形参的格式: 数据类型 ... 变量名

    ​ 2.2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,多个

    ​ 2.3 可变个数形参方法与本类中方法名相同,形参不同的方法之间构成重载。

    ​ 2.4 数据类型 ... 变量名数据类型[] 变量名 不构成重载,即不可共存

    ​ 2.5 可变个数形参 在方法的形参中,必须声明在末尾,且最多只能声明一个可变形参。

public class MethodArgsTest{
	
	public static void main(String[] args){
		
		MethodArgsTest test = new MethodArgsTest();
		test.show(12);
		test.show("hello");//show(String)
        test.show("hello","world");//show(String ... strs)	多个形参
        test.show();//show(String ... strs)		0个形参
        test.show(new String[]{"AA","BB","CC"});//show(String ... strs)   传 数组
	}
	
	
	public void show(int i){
		
	}
	
	public void show(String s){
		System.out.println("show(String)");
	}
	
	public void show(String ... strs){
		System.out.println("show(String ... strs)");
        //遍历,即把 strs 当做 数组
        for(int i=0;i<strs.length;i++){
            System.out.println(strs[i]);
        }
	}
    
    //可变参数形参,必须声明在末尾
    public void show(int i,String ... args){
        
    }
    
    
}

4.6.3 方法参数的值传递机制

1. 关于变量的赋值:

​ 如果变量是基本数据类型,此时赋值的是 变量所保存的数据值

​ 如果变量是引用数据类型,此时赋值的是 变量所保存的数据的地址值

public class ValueTransferTest{
	
	public static void main(String[] args){
		
        System.out.println("*************基本数据类型:*************");
        
		int m = 10;
		int n = m;
		System.out.println("m = "+ m + ", n = "+n);//m = 10, n = 10
		
        n = 20;
        System.out.println("m = "+ m + ", n = "+n);//m = 10, n = 20
        
        System.out.println("*************引用数据类型:*************");
        
        Order o1 = new Order();
        o1.orderId = 1001;
        
        Order o2 = o1;//把 o1 的 地址值 赋给 o2
        
        System.out.println("o1.orderId = "+ o1.orderId +
                           ", o2.orderId = "+ o2.orderId);//1001 1001
        
        o2.orderId = 1002;
        
        System.out.println("o1.orderId = "+ o1.orderId +
                           ", o2.orderId = "+ o2.orderId);//1002 1002
        
	}
    
}

class order{
    int orderId;
        
}

2. 方法的形参的传递机制:值传递

​ 若参数是基本数据类型,则实参传递给形参的是 实参真实存储的数据值

​ 若参数是引用数据类型,则实参传递给形参的是 实参存储数据的地址值

public class ValueTransferTest2{
	
	public static void main(String[] args){
        Data data = new Data();
        data.m=10;
        data.n=20;
        
        System.out.println("m = "+ m + ", n = "+n);//m=10  n=20
        
        ValueTransferTest2 test =new ValueTransferTest2();
        test.swap(data);//传地址
        
        System.out.println("m = "+ m + ", n = "+n);//m=20  n=10
    }
    
    public void swap(Data data){
        int temp=data.m;
        data.m=data.n;
        data.n=temp;
    }
    
}

class Data{
    int m;
    int n;
}

P211

4.6.4 递归方法(Recursion)

1、何为递归?——方法自己调用自己。

2、递归分类:直接递归,间接递归。

3、说明:

  • 递归方法包含了一种“隐式循环”
  • 递归方法会“重复执行”某段代码,但这种重复无须循环控制
  • 递归一定要向“已知方向“递归,否则这种递归就成了无穷递归,类似于”死循环“,最终导致”栈内存溢出“

4.7 package与import关键字使用

4.7.1 package关键字的使用

1、说明

package 包名.子包名
  • package:包 (所在公司域名倒置:com.atguigu.xxx 不能 java.xx)声明在首行
  • package用于指定文件中定义的类、接口等结构所在的包
  • package作为Java源文件的第一条语句出现;若缺省,则指定为无名包。
  • 包对应文件系统的目录,用“.”来指明包(目录)的层次
  • 包名,属于标识符,满足标识符命名的规则和规范(全部小写
  • 同一个包下可声明多个结构(类、接口),但不能定义同名结构

2、包的作用

  • 包可以包含 类 和 子包 , 划分项目层次,便于管理
  • 帮助管理大型软件系统(如 MVC设计模式:视图模型Viewer层,控制器Controller层,数据模型Model层)
  • 解决类命名冲突问题
  • 控制访问权限

3、JDK中主要的包

java.lang ----Java语言核心类,如String、Math、Integer、System、Thread

java.net ----包含执行与网络相关的雷和接口

java.io ----包含能提供多种输入、输出功能的类

java.util ----包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数

java.text ----包含一些java格式化相关的类

java.sql ----包含了java进行JDBC数据库编程的相关类、接口

java.awt ----包含了构成抽象窗口工具集(abstract window toolkits)的多个类

4.7.2 import关键字的使用

import:导入 类

import 包名.类名
  • import声明在包的声明和类的声明之间

  • 若使用 “ a.* ” 导入结构,则可以使用 a包下的所有类

  • 若是 lang包 下的类,或是 当前包 下的,则可 省略import

  • 如果已经导入 java.a包 下的类,那么如果使用 a包的子包 下的类,仍然需要导入

  • 使用不同包下的同名的类:使用全类名的方式

    import java.util.Date;
    import java.sql.Date;
    
    //Date可以使用import方式指明
    Date date = new Date();
    //使用全类名的方式
    java.sql.Date date1 = new java.sql.Date(121212);
    
  • import static组合的使用:调用指定类或接口下的静态的属性或方法

    import static java.lang.System.out;
    
    out.println("hello");
    

4.8 类的成员之三:构造器(Constructor)

4.8.1 构造器的作用

  1. 搭配new关键字,创建类的对象
  2. 在创建对象的同时,给对象的相关属性赋值(初始化对象的成员变量)

4.8.2 构造器使用

  • 声明格式: 权限修饰符 类名(形参列表){}
  • 创建类以后,在没有显示提供任何构造器的情况下,系统会默认提供一个 空参的构造器,且构造器的权限与类声明的权限相同。
  • 一旦类中显示声明了构造器,则系统不再提供 默认的空参的构造器。
  • 一个类中可以声明多个构造器,彼此之间构成重载。

4.8.3 问题

  1. 构造方法和普通方法的区别

    编写代码的角度:没有共同点。声明格式、作用都不同。

    字节码文件角度:构造器会以<init>()方法的形态呈现,用以初始化对象。

4.9 面向对象特征之一:封装性

4.9.1 为什么需要封装性?

面向对象开发原则:“高内聚、低耦合”

内聚:指一个模块内各个元素彼此结合的紧密程度。(重用,独立)

耦合:之一个软件结构内不同模块之间互联程度的度量。(牵一发而动全身)

理论上:

高内聚:类的内部数据操作自己完成,不允许外部干涉;

​ (Java程序通常以类的形态呈现,相关的功能封装到方法中)

低耦合:仅暴露少量的方法给外部使用,尽量方便外部调用。

​ (给相关的类、方法设置权限,把该隐藏的隐藏起来,该暴露的暴露出去)

通俗来说:

​ 把该隐藏的隐藏起来,把该暴露的暴露出去。

4.9.2 如何体现数据封装?

  1. 权限修饰符

​ java规定了4种权限修饰,分别是:private、缺省、protected、public

  1. 作用(什么是封装性?)

​ 我们可以用4种权限修饰来修饰类及类的内部成员,当这些成员被调用时,体现可见性的大小。

  1. 使用
package com.atguigu08.constructor;
  1. 权限修饰符访问范围
  • 实现封装 就是 控制类或成员的可见性范围 ,这就需要依赖权限修饰符(访问修饰符)来控制。
修饰符 本类内部 本包内 其他包的子类 其他包非子类
private × × ×
缺省 × ×
protected ×
public
  • 具体修饰的结构:
    • 外部类:public缺省
    • 成员变量、成员方法、构造器、成员内部类:publicprotected缺省private

  • 开发中4种权限使用频率:
    • 比较高:public、private
    • 比较低:缺省、protected

4.9.3 封装性的体现

  • 场景1:私有化(private)类的属性,提供公共(public)的get和set方法,对此属性进行获取或修改
  • 场景2:将类中不需要对外暴露的方法,设置为private
  • 场景3:单例模式中构造器private的,避免在类的外部创建实例(在static关键字后讲)

4.9.4 问题

  1. main方法的public能不能换成private?为什么?

    能。但换成private之后就不能作为程序的入口了,就只是一个普通的方法。

4.10 阶段性知识补充

4.10.1 类中属性赋值过程

1、赋值方式:

  1. 默认初始化

  2. 显式初始化

  3. 构造器中初始化


  4. 通过“对象.方法”的方式赋值

  5. 通过“对象.属性”的方式赋值

2、赋值顺序:

​ ① - ② - ③ - ④/⑤

3、以上操作在对象创建过程中可以执行多少次

  • 只能执行1次:①②③
  • 可以多次执行:④⑤

4.10.2 JavaBean

  • JavaBean是一种Java语言写成的可重用组件。
  • 所谓JavaBean,是指符合如下标准的Java类:
    • 类是公共的
    • 有一个无参的共同的构造器
    • 有属性,且有对应的get、set方法

4.10.3 UML类图

​ UML(Unified Modeling Language,统一建模语言),用来描述软件模型和架构的图形化语言。

posted @ 2023-04-01 18:36  榆钱儿。  阅读(23)  评论(0编辑  收藏  举报