Java学习笔记:类和对象
一、类和对象的创建
类(class)是一种自定义的数据类型。通过类来创建对象,对象就是一个具体的实例。
定义一个新的数据类型 class 类名{ }
根据类创建一个实例 类名 实例名 = new 类名();
内存分配机制(JVM)
存储区域: 寄存器(处理器内部)、堆栈(通用RAM)、堆(RAM区)、常量存储(程序内部或ROM)、非RAM存储
实例名(对象名)是对在内存中的堆和方法区的对象的引用。
对象在内存中的存在形式: 在方法区加载类的相关信息(属性、方法),在new一个新的对象之后会在堆中分配地址用于存放相关信息(相关类型的初始值),方法区的常量池中分配一个空间用于存放数据(字符串等)。接下来将这个地址返回给栈,创建的对象名会引用这个栈中的地址进行相关操作。
类和对象的内存分配机制: 先加载类信息(属性和方法信息,只会加载一次),在堆中分配空间进行默认初始化,把地址赋给对象名,对象名就指向对象,进行指定初始化。
二、属性/成员变量
成员变量是用来表示属性的,属性是类的一个组成部分,一般是基本数据类型也可以是引用类型。
-
四种访问修饰符:public、proctected、默认、private
-
属性类型可以为任意类型,包括基本类型或引用类型。
-
属性如果不赋值,则会有默认值。(int 0,short 0,byte 0,long 0,float 0.0,double 0.0,char \u0000,boolean false,String null)
访问属性,在创建一个对象之后 对象名.属性名;
三、成员方法
在类中定义的函数称为方法
访问修饰符 返回数据类型 方法名(参数列表){方法体;}
public void main(String[] args{
System.out.println("Hello,World!");
}
//public表示方法为公开,void表示方法没有返回值,main是方法名,String[]为形参列表
//{ }内为方法体,写要执行的代码。
public int getSum(int num1,int num2){
int res = num1 + num2;
return res;
}
//public表示方法为公开,int表示方法执行后返回一个int类型的值
//(int num1,int num2)是形参列表,可以接收传入的两个数
//return res表示把res的值返回。
方法的调用:对象名.方法名(相关参数);
//一个方法最多有一个返回值,使用数组可以返回多个数据
int[] resArr = new int[2];
resArr[0] = n1 + n2;
resArr[1] = n1 - n2;
return resArr;
-
返回类型可以为任意类型(基本类型、引用类型),方法有要求返回数据类型必须和return的值一致或兼容。
-
方法定义时的参数称为形式参数;方法调用时的参数称为实际参数,形参与实参的类型要兼容,个数、顺序一致。
-
方法里不能再定义方法,方法不能嵌套定义。
-
同一个类中的方法调用直接调用,跨类中的方法调用需要通过对象名调用(方法访问修饰符相关)
方法的调用机制
-
首先在栈中创建一个空间(main栈),在main栈里执行了创建一个对象的代码,在堆中就产生了一个对象。当执行到对象所调用的方法时,会在栈中再开一个独立的空间。
-
在新开的独立空间中进行所调用的方法的执行。
-
当方法执行完毕或者执行到return语句的时候,会将结果返回到main栈,独立空间被销毁(释放)
-
继续执行main栈中的代码,执行完毕之后main栈也被释放(整个程序结束)
四、方法的传参机制
引用类型传递的是地址(传递也是值,但是值是地址),可以通过形式参数影响实际参数。
-
在执行一个方法时,就在栈中创建一个新的受保护的独立空间。其局部变量是独立的,不会相互影响。
-
如果方法使用的是应用类型变量,就会共享该引用类型的数据。
-
当一个方法执行完毕或者遇到了return就会返回,遵守谁调用就将结果返回给谁,该方法也执行完毕。
五、static关键字
通过使用static关键字,可以实现即使从未创建某个类的任何对象,也可以调用其static方法或访问其static域。
static可以创建或使用与其类型相同的被命名对象,可以在不创建任何对象的前提调用。
public class Object01 {
public static void main(String[] args){
Fun.fun2();
Fun.test3 = 6;
}
}
class Fun {
int test1;
static int test3;
public static void fun2(){
System.out.println("Static");
}
}
六、重载
在同一个类中可以有相同名字的方法,但是形参列表要不一致。
在方法重载中,方法名必须相同,参数类型或个数或顺序至少有一样不同,参数名无要求,返回类型无要求。
public class Object01 {
public static void main(String[] args){
MyCalculator myCalculator = new MyCalculator();
myCalculator.calculate(1,2);
myCalculator.calculate(1,2,3);
}
}
class MyCalculator{
public int calculate(int n1,int n2){
int res = n1 + n2;
return res;
}
public int calculate(int n1,int n2,int n3){
int res = n1 + n2 + n3;
return res;
}
}
七、可变参数
将一个类中多个同名同功能但是参数个数不同的方法封装成一个方法。
访问修饰符 返回类型 方法名(数据类型… 形参名){代码块;}
可变参数的实参可以是0个或者多个,可变参数的实参可以为数组,可变参数的本质就是数组。
可变参数可以和普通类型的参数一起放在形参列表,但可变参数必须在最后一个。
一个形参列表只能出现一个可变参数。
class Method{
public int sum(int... nums){
int res = 0;
for (int i = 0;i < nums.length;i++){
res += nums[i];
}
return res;
}
}
八、作用域
局部变量是指在成员方法中定义的变量,全局变量(属性)的作用域为整个类。
-
全局变量不用赋值,直接使用(存在默认值);局部变量必须赋值之后才可以使用。
-
属性和局部变量可以重名,访问时遵循就近原则,在同一个作用域中变量不能重名。
-
属性伴随着对象的创建而创建,局部变量伴随这代码块的执行而创建(在一次方法调用中)
-
全局变量可以加修饰符,也可以被本类或其他类通过对象调用而使用;局部变量不能加修饰符,只能在对应的方法中使用。
class Scope{
int i;
String j;
public void scope(){
int h;
System.out.println(h);
System.out.println(i);
}
}
java: 可能尚未初始化变量h
九、构造方法(构造器)
构造器是类的一种特殊的方法,它的主要作用是完成对于新对象的初始化,在创建对象时系统会自动调用该类的构造器完成对对象的初始化。
修饰符 方法名(形参列表){方法体}
-
构造器的修饰符可以默认,没有返回值(不能写void),方法名和类名必须一样,参数列表跟成员方法的一致。
-
一个类可以定义多个构造器(构造器重载),构造器是完成对象的初始化,不是创建对象,在创建对象时系统会自动的调用该类的构造方法。
-
系统会自动给类生成一个默认无参数的构造方法(默认构造方法),一旦自己定义了一个构造器,默认的构造器就被覆盖了,不能再使用默认的。(也可以显式定义)
public class Object01 {
public static void main(String[] args){
Constructor constructor = new Constructor("you",22);
System.out.println(constructor.i);
System.out.println(constructor.j);
}
}
class Constructor{
String i;
int j;
Constructor(){} //显式定义
public Constructor(String ii,int jj){
i = ii;
j = jj;
}
}
十、this关键字
this跟对象名引用的堆中的对象的地址相同,哪个对象调用,this就代表哪个对象。
-
jvm会给每个对象分配this,代表当前对象,使用this可以使构造器的形参能够直接写成属性名。
-
this关键字可以用于访问本类的属性、方法、构造器,用于区分当前类的属性和局部变量。不能在类的外部使用。
访问成员方法: this.方法名(参数列表);
访问构造器,只能在构造器中使用,必须放在第一条语句: this(参数列表);
public class Object01 {
public static void main(String[] args){
Constructor constructor = new Constructor("you",22);
constructor.hashCode();//查看创建的对象的地址
System.out.println(constructor.hashCode());
}
}
class Constructor{
String i;
int j;
public Constructor(String i,int j){
this.i = i; //this.i当前对象的属性i
this.j = j;
System.out.println(this.hashCode());//查看this的地址
}
}
381259350
381259350