类和对象:
类(Class)
类是一个模板或蓝图,它定义了一组具有相同属性(数据)和方法(行为)的对象的特征。可以把类比作建筑的设计图纸,它描述了建筑将会有哪些部分(比如房间、门窗)和功能(比如供暖、照明)。
在 Java 中,类通过关键字 class
定义,它包含了两大部分:
属性:这些是类中定义的变量,用于存储对象的状态或数据。
方法(也叫做成员函数):这些是类中定义的函数,用于定义对象可以执行的操作。
java">public class Car {// 属性String color;int year;// 方法void accelerate() {System.out.println("Car is accelerating.");}
}
对象(Object)
对象是类的一个实例。如果说类是设计图纸,那么对象就是根据这个图纸建造的实际建筑。每个对象都拥有类中定义的属性和方法的具体实例。
创建类的实例(对象)时,每个对象都会拥有独立的属性集,这意味着每个对象的属性可以有不同的值,但所有对象都会共享相同的方法。
java">public class TestCar {public static void main(String[] args) {// 创建 Car 类的对象Car myCar = new Car();// 访问属性并赋值myCar.color = "Red";myCar.year = 2021;// 调用方法myCar.accelerate();}
}
构造方法:
构造方法是一种特殊类型的方法,在 Java 中用于初始化新创建的对象。构造方法的主要特点是它与类同名并且没有返回类型,不仅仅是没有 void
,而是连返回类型声明都没有。
java"> //默认构造方法public Student(){System.out.println("默认构造方法");}//含参数的构造方法public Student(String name, int age){this.name = name;this.age = age;}
在 Java 中,如果一个类没有显式定义任何构造方法,编译器会为这个类提供一个默认的无参数构造方法。但如果你定义了至少一个构造方法(无论是有参数还是无参数的),编译器就不会提供默认的构造方法。因此,如果你想让你的类在不提供任何特定参数的情况下也能创建对象,你需要显式定义一个无参数的构造方法。
构造方法的重载:
构造方法重载的规则:
java">class Person {String name;int age;// 无参构造方法public Person() {this.name = "Unknown";this.age = 0;}// 带一个参数的构造方法public Person(String name) {this.name = name;this.age = 0;}// 带两个参数的构造方法public Person(String name, int age) {this.name = name;this.age = age;}// 显示信息的方法public void display() {System.out.println("Name: " + name + ", Age: " + age);}
}public class Main {public static void main(String[] args) {Person p1 = new Person(); // 使用无参构造方法Person p2 = new Person("Alice"); // 使用带一个参数的构造方法Person p3 = new Person("Bob", 25); // 使用带两个参数的构造方法p1.display();p2.display();p3.display();}
}
输出:
java">Name: Unknown, Age: 0
Name: Alice, Age: 0
Name: Bob, Age: 25
通过构造方式的重载,可以通过多种方法创建对象
标准的JavaBean类:
java">package day2;public class Student {//private私有属性,表示只在这个类里面可以调用//set方法:给成员变量赋值//get方法:对外提供成员变量的值//this:表示当前方法调用者的地址private String name;public void setName(String name){this.name = name;}public String getName(){return this.name;}private int age;public void setAge(int age){if(age >= 6 ) this.age = age;}public int getAge(){return this.age;}//构造方法的名字应该和对象名字相同//构造方法没有返回值,所以不需要写void这些返回类型。//当不存在构造方法是,系统会自动生成默认构造方法,// 一旦我们手写了构造方法,系统也不会生成默认方构造方法了。//默认构造方法public Student(){System.out.println("默认构造方法");}//含参数的构造方法public Student(String name, int age){this.name = name;this.age = age;}//其他行为。
}
在主方法中创建对象:
java">package day2;public class StudentTest {public static void main(String[] args) {Student s1 = new Student();s1.setName("李四");s1.setAge(20);//使用有参数的构造方法,就不需要调用set方法了Student s2 = new Student("张三",24);}
}
this关键字:
理解堆与栈:
1. 栈(Stack)
栈是一种用于管理方法调用和局部变量的内存区域,它遵循后进先出(LIFO)的原则。每次调用一个方法时,都会在栈中为该方法分配一个新的栈帧,存储该方法的局部变量、方法参数和返回地址等。
特点:
- 快速访问:栈内存的分配和回收非常快,因为它是直接由操作系统管理的,每个线程都有自己的栈。
- 局部变量存储:局部变量和方法参数都存储在栈中。当方法调用结束时,栈帧会被自动销毁,所有局部变量都会被回收。
- 线程隔离:每个线程都有自己的栈,因此线程之间的栈是相互独立的。
- 空间有限:栈的大小通常较小(可以在 JVM 启动时指定),并且栈溢出(StackOverflowError)通常是由递归或深度嵌套方法引起的。
示例:
java">public void methodA() {int x = 10; // x 是一个局部变量,存储在栈中methodB();
}public void methodB() {int y = 20; // y 是一个局部变量,存储在栈中
}
在这个例子中,当 methodA
被调用时,它的局部变量 x
存储在栈中。当 methodB
被调用时,y
也会被存储在栈中。
2. 堆(Heap)
堆是一个全局的内存区域,用于存储所有的对象。JVM 在堆上分配对象内存,并由垃圾收集器(Garbage Collector)负责管理堆上的对象的生命周期。
特点:
- 对象存储:Java 中所有通过
new
关键字创建的对象都存储在堆中。无论是局部变量还是全局变量,只要是对象引用,都指向堆中的实际对象。 - 共享内存:堆是线程共享的,所有线程可以访问堆中的对象。因此需要进行同步管理,以避免线程安全问题。
- 垃圾回收:对象的分配和回收由 JVM 的垃圾收集器自动管理。垃圾回收会扫描堆中的无用对象并回收内存。
- 存储时间长:与栈不同,堆中的对象生命周期较长,直到没有任何引用指向该对象时,它才会被垃圾回收。
示例:
java">public class Example {int[] numbers = new int[10]; // numbers 数组存储在堆中
}
3. 堆与栈的协同工作
栈中的局部变量(比如引用变量)可以指向堆中的对象。比如,在方法内创建的对象,它们的引用会存储在栈中,而对象本身存储在堆中。当方法结束时,栈上的引用被销毁,但堆中的对象仍然存在,直到垃圾收集器回收它。
示例:
java">public class Main {public static void main(String[] args) {Person person = new Person(); // person 引用存储在栈中,但对象在堆中}
}
在这个例子中,person
引用变量在栈中,而 Person
对象存储在堆中。
总结
- 栈:存储局部变量和方法调用信息,速度快,但空间有限。
- 堆:存储所有对象,由垃圾收集器管理,空间大但访问速度相对较慢