Java基础知识(四) -- 面向对象(上)

1.概述

  Java语言是一种面向对象的程序设计语言,而面向对象思想(OOP)是一种程序设计思想,在面向对象思想的指引下,使用Java语言去设计、开发计算机程序。这里的对象 泛指现实中一切事物,每种事物都具备自己的属性行为

  面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。它区别于面向过程思想(POP),强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。面向对象的语言中,包含了三大基本特征,即封装继承多态

2.类和对象

2.1 什么是类?

  • :是一类具有相同特性的事物的抽象描述,是一组相关属性行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。

现实中,描述一类事物:

  • 属性:就是该事物的状态信息。
  • 行为:就是该事物能够做什么。

举例:小猫。

​ 属性:名字、体重、年龄、颜色。

​ 行为:走、跑、叫。

2.2 什么是对象?

  • 对象 :是一类事物的具体体现。对象是类的一个实例 ,必然具备该类事物的属性和行为。现实中,一类事物的一个实例:一只小猫 。
    • 属性:tom、5kg、2 years、yellow。
    • 行为:溜墙根走、蹦跶的跑、喵喵叫。

2.3 类与对象关系

  • 类是对一类事物的描述,是抽象的
  • 对象是一类事物的实例,是具体的
  • 类是对象的模板,对象是类的实体

3.类的定义和对象的创建

Java中用class描述事物也是如此:

  • 成员变量 :对应事物的属性
  • 成员方法 :对应事物的行为

3.1 类的创建

类的定义格式:

java 复制代码
public class ClassName{
    //成员变量
    //成员方法
}
  • 定义类 :定义类的成员,包括成员变量成员方法
  • 成员变量 :和定义变量几乎是一样的。只不过位置发生了改变。在类中,方法外
  • 成员方法:和main方法格式类似。只不过功能和形式更丰富了。
java 复制代码
public class Person{
    //成员变量
    String name; //姓名
    int age; // 年龄
    boolean isMarried;
    
    public void walk(){
        System.out.println("人走路...")
    }
    
    public String display(){
        return "名字:"+ name + ",年龄:" + age + ",Married:" + isMarried;
    }
}

3.2 对象的创建

对象的定义格式

java 复制代码
new 类名() // 匿名对象
    
// 把创建的对象用一个引用数据类型的变量保存起来    
类型 对象名 = new 类名();

Q:对象名中存储的是什么? A: 对象地址

java 复制代码
//如果两个类都在一个.java源文件中,只能有一个类是public的
class Student{
    
}
public class TestStudent{
    //Java程序的入口
    public static void main(String[] args){
        System.out.println(new Student());//JavaBase.Student@4554617c

        Student stu = new Student();
        System.out.println(stu);//JavaBase.Student@74a14482
        
        int[] arr = new int[5];
		System.out.println(arr);//[I@1540e19d
    }
}

从上述的运行结果可以看出, 学生对象和数组对象类似,直接打印对象名和数组名都是显示"类型@对象的hashCode值",所以类、数组都是引用数据类型,引用数据类型的变量中存储的是对象的地址,或者说指向堆中对象的首地址。

3.3 成员变量

3.3.1 成员变量分类
  • 实例变量:没有static修饰,也叫对象属性,属于某个对象的。
  • 静态变量:有static修饰,也叫类变量,属于整个类的,不是属于某个实例。
3.3.2 如何声明成员变量?
java 复制代码
【修饰符】 class 类名{
    【修饰符】 数据类型 属性名; // 属性有默认值
    【修饰符】 数据类型 属性名 = 值; // 属性有初始值
}

例:声明一个中国人

java 复制代码
class Chinese{
    static String country;
    String name;
    char gender = '男'; // 显式赋值
}
3.3.3 如何在类外访问成员变量?
1.类变量
java 复制代码
类名.静态成员变量  //推荐
对象名.静态成员变量 //不推荐
2.实例变量
java 复制代码
对象名.普通成员变量  //只能使用这种方式
java 复制代码
public class TestChinese{
    public static void main(String[] args){
        // 类变量的访问方式:类名.静态成员变量
        System.out.println(Chinese.country)
        
        Chinese c1 = new Chinese();
		//对象名.普通成员变量
		System.out.println(c1.name);
		//静态的成员变量也可以通过对象.进行访问
		//对象名.普通成员变量
		System.out.println(c1.country);
        System.out.println(c1.gender);
    }
}

class Chinese{
    static String country;
    String name;
    char gender = '男';
}
3.3.4 成员变量的特点
1.成员变量有默认值
基本类型 整数(byte,short,int,long) 0
浮点数(float,double) 0.0
字符(char) '\u0000'
布尔(boolean) false
引用类型 数组,类,接口 null
2.类变量的值是所有对象共享,而实例变量的值是属于每个对象
java 复制代码
public class TestChinese {
    public static void main(String[] args) {
        Chinese c1 = new Chinese();
        Chinese c2 = new Chinese();

        c1.name = "张三";
        c2.name = "李四";
        c2.gender = '女';
        Chinese.country = "中国";//推荐

        System.out.println("c1.country = " + c1.country + ",c1.name = " + c1.name + ",c1.gender = " + c1.gender);
        System.out.println("c2.country = " + c2.country + ",c2.name = " + c2.name + ",c2.gender = " + c2.gender);
    }
}

class Chinese {
    static String country;
    String name;
    char gender = '男';
}

/** 输出结果:
  * c1.country = 中国,c1.name = 张三,c1.gender = 男
  * c2.country = 中国,c2.name = 李四,c2.gender = 女
/
3.3.5 成员变量的内存图

  内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来。编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。Java虚拟机要运行程序,必须要对内存进行空间的分配和管理,每一片区域都有特定的处理数据方式和内存管理方式。

  • 堆(Heap):存储对象(包括数组对象),new来创建的,都存储在堆内存。
  • 方法区(Method Area):存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
  • 本地方法栈(Native Method Stack):为当程序中调用了native的本地方法时,本地方法执行期间的内存区域。
  • 程序计数器(Program Counter Register):程序计数器是CPU中的寄存器,它包含每一个线程下一条要执行的指令的地址。
  • 虚拟机栈(VM Stack): 用于存储正在执行的每个Java方法的局部变量表等。局部变量表存放了编译期可知长度的各种基本数据类型、对象引用,方法执行完,自动释放。

举例说明

java 复制代码
package JavaBase;


public class Test08FieldSave {
    public static void main(String[] args) {
        Chinese c1 = new Chinese();
        c1.name = "张三";
        //静态变量,也可以使用"对象名."进行访问
        System.out.println(c1.country);
        //普通成员变量通过"对象名."进行访问
        System.out.println(c1.name);


        Chinese c2 = new Chinese();
        c2.name = "李四";
        System.out.println(c2.country);
        System.out.println(c2.name);

        System.out.println("--------------------------------------");
        //其中一个对象将静态变量的值修改了,其他对象都会改变
        //因为静态变量只存一份
        c1.country = "中华人民共和国";
        System.out.println(c1.country);
        System.out.println(c2.country);
        System.out.println(Chinese.country);


        //其中一个对象将普通成员变量修改了,其他对象不受影响
        c1.name = "张三丰";
        System.out.println(c1.name);
        System.out.println(c2.name);
    }

}

class Chinese {
    //静态成员变量,所有中国人的国家的名称是一样,只需要存储一份
    static String country = "中国";
    //普通成员变量,每一个中国人的姓名是独立,每一个对象单独存储
    String name;
}
/*
输出结果:
中国
张三
中国
李四
--------------------------------------
中华人民共和国
中华人民共和国
中华人民共和国
张三丰
李四
*/

3.4 成员方法

3.4.1 方法的概念

  方法也叫函数,是一个独立功能的定义,是一个类中最基本的功能单元。把一个功能封装为方法的目的是,可以实现代码重用,从而简少代码量。

3.4.2 方法的原则

  方法的使用原则:

  • (1) 必须先声明后使用

    类,变量,方法等都要先声明后使用

  • (2) 不调用不执行,调用一次执行一次。

3.4.3 成员方法的分类

  成员方法分为两类:

  • 实例方法:没有static修饰的方法,必须通过实例对象来调用。
  • 静态方法:有static修饰的方法,也叫类方法,可以由类名来调用。
3.4.4 如何声明成员方法?
    1. 方法声明的位置必须在类中方法外
    1. 语法格式
    java 复制代码
    【修饰符】 返回值类型 方法名(【参数列表:参数类型1 参数名1,参数类型2 参数名, ...... 】){
            方法体;
            【return 返回值;】
    }

    格式详解:

    • 修饰符: 修饰符后面一一介绍,例如:public,static等都是修饰符;
    • 返回值类型: 表示方法运行的结果的数据类型,方法执行后将结果返回到调用者【基本数据类型/引用数据类型/void】;
    • 方法名:见名知意,能准确代表该方法功能的名字;
    • 方法体:特定功能代码;
    • return:结束方法,并将方法的结果返回;
      • 如果返回值类型不是void,方法体中必须保证一定有return 返回值; 并且要求该返回值结果的类型与声明的返回值类型一致或兼容。
      • 如果返回值类型为void时,return 后面不用跟返回值,甚至也可以没有return语句。
      • return语句后面就不能再写其他代码了,否则会报错:Unreachable code

实例:

java 复制代码
类{
    方法1(){
        
    }
    方法2(){
        
    }
}
3.4.5 如何在其他类中调用方法?
1.实例方法
java 复制代码
对象名.普通方法(【实参列表】)  //必须通过对象来访问
java 复制代码
public class TestCircle {
	public static void main(String[] args) {
		Circle c1 = new Circle();
		c1.radius = 1.2;
		System.out.println("c1的面积:" + c1.area());
		//普通方法只能通过"对象."进行访问
//		System.out.println("c1的面积:" + Circle.area());
        
		Circle c2 = new Circle();
		c2.radius = 2.5;
		System.out.println("c2的面积:" + c2.area());
	}
}
class Circle{
	double radius;
	public double area() {
		return Math.PI * radius * radius;
	}
}
2.类方法
java 复制代码
类名.类方法(【实参列表】)  //推荐
对象名.类方法(【实参列表】) //不推荐

示例:

java 复制代码
public class TestCount {
	public static void main(String[] args) {
		System.out.println(CountTools.max(4, 1));
		
		//静态方法也可以通过"对象."访问,就是麻烦点
		CountTools c = new CountTools();
		System.out.println(c.max(2, 5));
	}
}
class CountTools{
	static int max(int a, int b) {
		return a > b ? a : b;
	}
}
3.形参与实参
  • 形参:在定义方法时方法名后面括号中声明的变量称为形式参数(简称形参)即形参出现在方法定义时。
  • 实参:调用方法时方法名后括号中使用的值/变量/表达式称为实际参数(简称实参)即实参出现在方法调用时。
  • 调用时,需要传"实参",实参的个数、类型、顺序顺序要与形参列表一一对应;如果方法没有形参,就不需要也不能传实参。
3.4.6 在本类中访问本类的成员变量和成员方法
  • 直接用,不需要加"对象名."和"类名."

  • 唯一例外:静态方法中不能直接访问本类的非静态的成员变量和成员方法

    java 复制代码
    class Circle{
    	double radius;
    	
    	//写一个方法,可以返回"圆对象"的详细信息
    	String getDetailInfo(){
    		return "半径:" + radius + ",面积:" + area() +",周长:" + perimeter();
    	}
    	
    	//写一个方法,可以返回"圆对象"的面积
    	double area(){
    		return Math.PI*radius*radius;
    	}
    	
    	//写一个方法,可以返回"圆对象"的周长
    	double perimeter(){
    		return 2*Math.PI*radius;
    	}
    }
3.4.7 方法调用内存分析

  方法不调用不执行,调用一次执行一次,每次调用会有一个入栈动作,即给当前方法开辟一块独立的内存区域,用于存储当前方法的局部变量的值,当方法执行结束后,会释放该内存,称为出栈,如果方法有返回值,就会把结果返回调用处,如果没有返回值,就直接结束,回到调用处继续执行下一条指令。

栈结构:先进后出,后进先出。

3.4.8 方法的参数传递机制

方法的参数传递机制:实参给形参赋值

  • 方法的形参是基本数据类型时,形参值的改变不会影响实参;
  • 方法的形参是引用数据类型时,形参地址值的改变不会影响实参,但是形参地址值里面的数据的改变会影响实参,例如,修改数组元素的值,或修改对象的属性值。
    • 注意:String、Integer等特殊类型容易错。

示例1:

java 复制代码
class Test{
    public static void swap(int a, int b){
        int temp = a;
        a = b;
        b = temp;
	}

	public static void main(String[] args){
        int x = 1;
        int y = 2;
        swap(x,y);//调用完之后,x与y的值不变
    }
}

示例2:

java 复制代码
class Test{
    public static void change(MyData my){
        my.num *= 2;
    }
    
    public static void main(String[] args){
        MyData m = new MyData();
        m.num = 1;
        
        change(m);//调用完之后,m对象的num属性值就变为2
    }
}

class MyData{
    int num;
}

4.成员变量与局部变量的区别

成员变量: 静态变量、实例变量

    1. 声明位置和方式
    • (1)静态变量:在类中方法外,并且有static修饰
    • (2)实例变量:在类中方法外,没有static修饰
    • (3)局部变量:在方法体{}中或方法的形参列表、代码块中
    1. 在内存中存储的位置不同
    • (1)静态变量:方法区
    • (2)实例变量:堆
    • (3)局部变量:栈
    1. 生命周期
    • (1)静态变量:和类的生命周期一样,因为它的值是该类所有对象共享的,早于对象的创建而存在。
    • (2)实例变量:和对象的生命周期一样,随着对象的创建而存在,随着对象被GC回收而消亡,而且每一个对象的实例变量是独立的。
    • (3)局部变量:和方法调用的生命周期一样,每一次方法被调用而在存在,随着方法执行的结束而消亡,而且每一次方法调用都是独立。
    1. 作用域
    • (1)静态变量和实例变量:不谈作用域。在本类中,唯一的限制,静态方法或静态代码块中不能使用非静态的,其他都可以直接使用。在其他类中,能不能使用看修饰符(public,protected,private等)。
    • (2)局部变量:有作用域。
    1. 修饰符
    • (1)静态变量:public,protected,private,final,volatile等,一定有的是static。
    • (2)实例变量:public,protected,private,final,volatile,transient等。
    • (3)局部变量:final。
    1. 默认值
    • (1)静态变量:有默认值
    • (2)实例变量:有默认值
    • (3)局部变量:没有,必须初始化;其中的形参比较特殊,靠实参给它初始化。

5.可变参数

  在JDK1.5之后,如果定义一个方法时,此时某个形参的类型可以确定,但是形参的个数不确定,那么可以使用可变参数。格式:

复制代码
【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型... 形参名){  }

要求:

(1)一个方法最多只能有一个可变参数

(2)如果一个方法包含可变参数,那么可变参数必须是形参列表的最后一个

复制代码
【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型[] 形参名){  }

只是后面这种定义,在调用时必须传递数组,而前者更灵活,既可以传递数组,又可以直接传递数组的元素,这样更灵活了。

6.方法重载

  • 方法重载:指在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返回值类型无关。
  • 参数列表:数据类型个数不同,数据类型不同,数据类型顺序不同。
  • 重载方法调用:JVM通过方法的参数列表,调用不同的方法。

示例1:比较两个数据是否相等

比较两个数据是否相等。参数类型分别为两个byte类型,两个short类型,两个int类型,两个long类型,并在main方法中进行测试。

java 复制代码
public class Method_Demo6 {
    public static void main(String[] args) {
        //定义不同数据类型的变量
        byte a = 10;
        byte b = 20;
        short c = 10;
        short d = 20;
        int e = 10;
        int f = 10;
        long g = 10;
        long h = 20;
        // 调用
        System.out.println(compare(a, b));
        System.out.println(compare(c, d));
        System.out.println(compare(e, f));
        System.out.println(compare(g, h));
    }
    // 两个byte类型的
    public static boolean compare(byte a, byte b) {
        System.out.println("byte");
        return a == b;
    }

    // 两个short类型的
    public static boolean compare(short a, short b) {
        System.out.println("short");
        return a == b;
    }

    // 两个int类型的
    public static boolean compare(int a, int b) {
        System.out.println("int");
        return a == b;
    }

    // 两个long类型的
    public static boolean compare(long a, long b) {
        System.out.println("long");
        return a == b;
    }
}

7.总结

相关推荐
Scott9999HH6 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔6 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社7 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海7 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖8 小时前
JDK 26 新特性详解
java·开发语言
马优晨8 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区10 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大11 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai11 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说11 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json