类与对象的关系
从类创建对象,有好几种说法——1. 创建一个对象。2. 实例化一个对象。3. 把类实例化。
对象内存布局
首先会在方法区里加载类的信息。然后对象的地址存放在栈中,真正的对象放在堆里。如果对象里的属性是基本数据类型,那么就存放在堆里,如果是引用数据类型,那么在堆中存放地址,数据存放在方法区里。
从概念或叫法上看:成员变量 = 属性 = 字段(field),属性是类的一个组成部分,一般是基本数据类型,也可是引用数据类型(对象,数组等)。
类里的方法也叫实例方法,类里的属性也叫实例变量。
内存
堆区:只存放类对象,线程共享,类中的成员变量都存放在堆区。
方法区:又叫静态存储区,存放class文件和静态数据,线程共享。
栈区:存放方法的局部变量,基本类型变量区。线程不共享。
对象创建流程
class Person {
int age = 90;
String name;
Person(String n, int a) {
name = n;
age = a;
}
}
//主函数
Person p = new Person("小王",20);
1. 加载Person类信息,只会加载一次。
2. 在堆中分配空间(地址)。
3. 完成对象初始化——(1)默认初始化,age = 0,name = null。(2)显式初始化,age = 90,name = null。(3)构造器的初始化,age = 20,name = 小王。
4. 把对象在堆中的地址,返回给p(p是对象名,也可以理解成是对象的引用)。
可变参数
Java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。
比如下面这几个方法,都是求和的函数,只不过参数个数不同,那么就可以改成一个方法。
public int sum(int n1, int n2) {
return n1 + n2;
}
public int sum(int n1, int n2, int n3) {
return n1 + n2 + n3;
}
public int sum(int n1, int n2, int n3, int n4) {
return n1 + n2 + n3 + n4;
}
public int sum(int... nums) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
return sum;
}
基本语法
访问修饰符 返回类型 方法名(数据类型... 形参名){}
使用细节
1. 可变参数的实参可以为0个或任意多个。
2. 可变参数的实参可以为数组。
Person a = new Person();
int[] b = { 1, 2, 3 };
System.out.println(a.sum(b));
3. 可变参数的本质就是数组,因此可以调用各种数组的方法(比如length等)。
4. 可变参数可以与普通类型的参数一起放在形参列表,但必须保证可变参数在最后。
public int sum(int... nums, double t) { //错误
public int sum(double t, int... nums) { //正确
5. 一个形参列表只能出现一个可变参数。
public int sum(int... nums, double... ds) { //错误
作用域
1. 简介
在Java中,主要的变量是 成员变量(也就是属性,也叫全局变量) 和 局部变量。局部变量一般是指在成员方法中定义的变量,成员变量则是在类中定义的变量。
全局变量作用域为整个类,局部变量作用域为定义它的代码块。
class Person {
int num; //全局变量
public void showScore() {
num = 10; //可以直接调用
}
}
public void showScore() {
int score = 100; //定义局部变量
}
public void test() {
score = 20; //这样就会报错,因为score只在showScore方法中可以使用
}
全局变量可以不赋值直接使用,因为有默认值。而局部变量必须赋值后才能使用,因为没有默认值。
class Person {
int num1;
public void test() {
int num2;
System.out.println(num1); //不会报错
System.out.println(num2); //会报错:没有进行初始化
}
}
2. 使用细节
1. 属性和局部变量可以重名,访问时遵循就近原则。
class Person {
int num1 = 10;
public void test() {
int num1 = 200000;
System.out.println(num1); //根据就近原则,输入200000
}
}
2. 在同一个作用域中(比如在同一个成员方法里),两个局部变量不能重名。
public void test() {
int num1 = 200000;
int num1 = 300; //报错
System.out.println(num1);
}
3. 属性的生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。局部变量生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁(也即一次方法的调用)。
4. 全局变量(属性)可以被本类使用,也可以被其它类使用(通过对象调用,当然前提得是public),而局部变量只能在本类的对应方法中使用。
class Person {
int num = 10;
}
class Test {
public void showNum(int n) {
System.out.print(n);
}
}
public static void main(String[] args) {
Person a = new Person();
Test b = new Test();
b.showNum(a.num); //通过对象调用属性
}
5. 修饰符不同:全局变量可以加修饰符,局部变量不可以加修饰符(只允许使用final)。
6. 只有在公共类中,才能够调用其他没有修饰符类的属性和方法。
public class Practice {
public static void main(String[] args) {
Person a = new Person(20, "wang");
Person b = new Person(20, "wang");
a.compareTo(b); //调用方法
}
}