Java面向对象编程-基础
目录
类与对象
类与对象的区别和联系
- 类是抽象的,概念的,代表一类事物,比如人类,猫类…, 即它是数据类型.
- 对象是具体的,实际的,代表一个具体事物,即是实例
- 类是对象的模板,对象是类的一个个体,对应一个实例
字符串本质上是一个引用类型,JVM把字符串放在方法去的常量池中。
对象的内存模型
Java对象的内存模型由Java虚拟机(JVM)负责管理。它描述了Java程序在内存中的分配、访问和交换的规则。Java对象的内存模型包括以下四个方面:
- 栈:存储局部变量、方法调用和返回值等信息。
- 堆:存储Java对象的实例。每个Java对象都有一个唯一的内存地址,该地址在堆上分配。
- 常量池:存放字符串常量和基本类型常量。
Java内存模型中,Java对象在创建后必须经过垃圾回收器(Garbage Collector)的清理,否则会占用内存。同时,由于Java对象是动态分配的,Java程序在访问Java对象时需要注意访问的是否合法,避免出现空指针异常(NullPointerException)。
字段
成员变量=属性=字段
class Car {
String name;//属性, 成员变量, 字段field
double price;
String color;
String[] master;//属性可以是基本数据类型,也可以是引用类型(对象,数组)
}
属性是类的一个组成部分,一般是基本数据类型, 也可是引用类型(对象,数组)。
注意:
-
属性的定义语法同变量,访问修饰符public、proctected、默认、private。
-
属性如果不赋值,有默认值。
- 基本数据类型属性默认初始值(8种):
- byte、short、int、long、float、double:默认值为0
- char:默认值为’\u0000’(ASCII码值为0)
- boolean:默认值为false
- 引用类型属性默认初始值
- 对象:默认值为null
成员方法
成员方法的调用机制
程序执行过程:
- 当程序执行到方法时,会开辟独立的栈空间。
- 当方法执行完毕,或执行到return语句时,就会返回。
- 返回到调用的方法的地方。
- 返回后,继续执行方法后面的代码。
- 当main方法执行完毕,整个程序退出。
成员方法的传参机制
在Java中,成员方法可以有不同类型的参数。基本数据类型的参数只能是有限的几种类型,而引用类型的参数可以是任何类型。
-
基本数据类型的参数:
基本数据类型的参数只能是Java的基本数据类型,包括整数(byte、short、int、long)、浮点数(float、double)和字符(char)。当我们调用一个基本数据类型的方法时,它只会传递一个该类型的值。
-
引用类型的参数(会改变对应地址的值):
当我们调用一个引用类型的方法时,它会接受一个引用类型的参数。引用类型的参数表示一个变量的内存地址,而不是变量本身的值。在调用一个引用类型的方法时,实际上传递的是引用类型参数所指向的变量的地址(不是c++中的引用)。
注意:两者都是传递值,和c++种引用类型传递不同。方法返回也是返回值(基本数据类型)或地址(引用类型)。
成员方法的递归调用
递归调用的重要原则
- 1.执行一个方法时,就创建一个新的受保护的独立空间(钱空间)
- 2.方法的局部变量是独立的,不会相互影响,比如n变量
- 3.如果方法中使用的是引用类型变量(比如数组,对象),就会共享该引用类型的数据。
- 4.递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError 5.当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就 将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕。
public class Recursion01 {
//编写一个main方法
public static void main(String[] args) {
T t1 = new T();
t1.test(4);//输出什么? n=2 n=3 n=4
int res = t1.factorial(5);
System.out.println("5的阶乘 res =" + res);
}
}
class T {
//分析
public void test(int n) {
if (n > 2) {
test(n - 1);
}
System.out.println("n=" + n);
}
//factorial 阶乘
public int factorial(int n) {
if (n == 1) {
return 1;
} else {
return factorial(n - 1) * n;
}
}
}
成员方法重载
Java中的方法重载指的是在同一个类中定义多个方法,它们具有相同的名称,但参数列表不同,返回类型不是判断重载的依据。编译器根据方法调用时传递的参数类型和数量来确定调用哪个方法。
- 方法名: 必须相同
- 形参列表: 必须不同(形参类型或个数或顺序,至少有一样不同,参数名无要求)
- 返回类型: 无要求
可变参数
java 允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法,通过可变参数实现。
基本语法
访问修饰符返回类型方法名(数据类型... 形参名) {
}
示例
public class VarParameter01 {
//编写一个main方法
public static void main(String[] args) {
HspMethod m = new HspMethod();
System.out.println(m.sum(1, 5, 100)); //106
System.out.println(m.sum(1,19)); //20
}
}
class HspMethod {
//1. int... 表示接受的是可变参数,类型是int ,即可以接收多个int(0-多)
//2. 使用可变参数时,可以当做数组来使用 即 nums 可以当做数组
//3. 遍历 nums 求和即可
public int sum(int... nums) {
//System.out.println("接收的参数个数=" + nums.length);
int res = 0;
for(int i = 0; i < nums.length; i++) {
res += nums[i];
}
return res;
}
}
public class method_ {
public static void main(String[] args) {
// 可变参数及成员函数传递机制
A a1 = new A();
A a2 = new A();
A a3 = new A();
test02(a1,a2,a3);
System.out.println(a1.a);
System.out.println(a2.a);
System.out.println(a3.a);
}
// 成员方法的传参机制
// 传递引用类型是传递地址而不是值
public static void test(A a){
a.a=20;
}
// 可变参数
public static void test02(A ...num){
for (int i = 0; i < num.length; i++) {
num[i].a=i;
}
}
}
class A{
public int a = 10;
}
注意:
- 可变参数的实参可以为0个或任意多个。
- 可变参数的本质就是数组。
- 可变参数的实参可以为数组。
- 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后。
- 一个形参列表中只能出现一个可变参数。
作用域
基本介绍
Java中,主要的变量有属性(成员变量)和局部变量。
Java中作用域分类:
- 全局变量:也就是属性,作用域为整个类体。
- 局部变量:也就是除了属性之外的其他变量,作用域为定义它的代码块中。
全局变量可不用赋初值,直接使用,因为有默认值。局部变量必赋初值才能使用,因为没有默认值。
使用细节
- 属性和局部变量可以重名,访问时遵循就近原则。
- 在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名。
- 生命周期不同
- 全局变量,生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。
- 局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。
- 作用域范围不同
- 全局变量:可以被本类使用,或其他类使用(通过对象调用)
- 局部变量:只能在本类中对应的方法中使用
- 修饰符不同
- 全局变量可以加修饰符
- 局部变量不可以加修饰符
构造方法
基本介绍
在Java中,构造器是一种特殊的方法,它在创建对象时自动调用。构造器可以用于初始化对象的属性,并执行其他必要的操作。
[修饰符] 类名(形参列表){
方法体;
}
使用细节
- 一个类可以定义多个不同的构造器,即构造器重载
- 比如:我们可以再给Person类定义一个构造器,用来创建对象的时候,只指定人名,不需要指定年龄。
- 构造器是完成对象的初始化,并不是创建对象。
- 如果程序员没有定义构造器,系统会自动生成一个默认无参构造器(也叫默认构造器)。比如Dog(){}, 使用javap指令反编译看看。
- 可以使用javap Dog.class 查看
- 一旦定义了有参构造器,系统不再提供无参构造器,可以显示定义无参构造器。
- 使用this指针调用其它构造器(C++中委托构造函数),只能在方法体的第一行。
this关键字
在JAVA中 this 是指代类自身实例化的一个对象。可以理解为对象本身的一个指针,更准确的说, this 代表当前对象的一个引用。
- 普通的直接引用
- 区分类成员属性和方法的形参
- 调用当前对象的其他方法
- 作为函数参数,表示传入对象本身
- 位置:在该类的任意位置都可以使用
- 调用构造函数
- 使用this指针调用其它构造器(C++中委托构造函数):this(参数列表)。
- 位置必须是第一条语句
- this 不能用于 static 方法。
public class test {
public static void main(String[] args) {
}
}
class TestPerson {
//编写一个main方法
public static void main(String[] args) {
Person p1 = new Person("mary", 20);
Person p2 = new Person("mary", 20);
System.out.println("p1和p2比较的结果=" + p1.compareTo(p2));
p1.print();
}
}
class Person {
String name;
int age;
//构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void print(){
System.out.println(this);
}
public void print2(){
this.print();
}
//compareTo比较方法
public boolean compareTo(Person p) {
return this.name.equals(p.name) && this.age == p.age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
访问修饰符
java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):
- 公开级别:用public 修饰,对外公开。
- 受保护级别:用protected 修饰,对子类和同一个包中的类公开。
- 默认级别:没有修饰符号,向同一个包的类公开。
- 私有级别:用private修饰,只有类本身可以访问,不对外公开。
注意:
- 修饰符可以用来修饰类中的属性,成员方法以及类。
- 只有默认修饰符和public才能修饰类,并且遵循上述访问权限的特点。
- 成员方法的访问规则和属性完全一样。
注意事项
null的引用
因为null可以赋给任何对象,当类进行变量初始化的时候,应该警惕null赋值情况。在代码其它部分可能会残生NullPointerException的异常,有时候很难定位。因此可以在构造函数中进行业务判断。
示例1
if(name==null)
this.name="unknown";
else
this.name = name;
示例2
public Person(String name, int age) {
this.name = Objects.requireNonNull(name,"the name cannot be null");
this.age = age;
}