一、堆栈方法区,方法的调用,递归等
1. 对象 类 堆 栈 方法区
Cat cat = new Cat();
cat.name = "小白";
cat.age = 12;
cat.color = "白色";
字符串是引用类型,会放在方法区的常量池里
① 属性的定义语法同变量,示例:访问修饰符 属性类型 属性名;
访问修饰符:public,proctected,默认,private——控制属性的访问范围
② 属性的定义类型可以为任意类型,包含基本类型和引用类型
③ 属性如果不赋值,有默认值,规则和数组一样
Person p1 = new Person();
//创建Person对象,p1是对象名,new Person()创建的对象空间(数据)才是真正的对象
//对象的属性默认值遵守数组规则,int 0, short 0, float 0.0, char \u0000 ......
如何创建对象:
//先声明再创建
Cat car; //声明对象Cat,在栈中声明,空间没有分配
cat = new Cat(); //创建,在堆中开辟空间,默认初始化,然后将地址值返回给栈中的声明
//直接创建
Cat cat = new Cat()
//先加载Cat类信息(属性和方法信息,只会加载一次),然后在堆中分配空间,
//默认初始化,把地址赋给cat,cat就指向对象,进行指定初始化
类与对象的内存分配机制:
① 栈:一般存放基本数据类型(局部变量)
② 堆:存放对象(Cat cat,数组等)
③方法区:常量池(常量,字符串),类加载信息
例题:
Person a = new Person();
a.age = 12;
a.name = "小明";
Person b;
b = a;
System.out.println(b.name);
b.age = 200;
b = null; //把地址置空
System.out.println(a.age);
System.out.println(b.age);
输出:
小明
200
b.age会出现异常(因为地址置空,空指针异常)
2. 一个方法最多有一个返回值,如果返回多个结果则返回数组
类包括方法和属性,一篇代码中可以有多个类,但只有一个主类
方法不能嵌套定义
同一个类中的方法可以直接调用
跨类调用:A类中的方法a想要调用B类中的方法b,需要在方法a中创建B类对象m,然后再调用方法b(m.b)
3. 方法调用总结:
① 当程序执行到方法时,就会开辟一个独立的空间(栈空间)
② 当方法执行完毕,或者执行到 return 语句时就会返回
③ 返回到调用方法的地方
④ 返回后,继续执行方法后面的代码
⑤ 当 main 方法(栈)执行完毕,整个程序退出
注:每次调用方法方法都在在栈中开辟一个独立的栈空间
4. 基本数据类型,传递的是值(拷贝),形参的任何改变不能影响实参
引用类型,传递的是地址,形参的改变会影响实参
5. 方法的递归调用
递归从顶级的栈开始返回
阶乘的递归
① 执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
② 方法的局部变量是独立的,不会相互影响
③ 如果方法中使用的是引用数据类型(如数组,对象),就会共享该引用类型的数据
④ 递归必须向退出递归的条件逼近,否则就是无限递归
⑤ 当一个方法执行完毕,或者遇到 return ,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕
二、方法重载
允许在同一个类里,多个同名方法的存在,但要求形参列表不同
好处:减轻了起名和记名的麻烦
注意事项:
方法名必须相同
形参列表必须不同(形参类型或个数或顺序,至少有一样保证不同,参数名无要求)
返回类型无要求(只有返回类型不同并没有构成重载,只是方法的重复使用)
三、可变参数
JAVA允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法,就可以通过可变参数实现
基本语法:访问修饰符 返回类型 方法名(数据类型... 形参名){ }
//int...表示接受的是可变参数,类型是int,即可以接收多个int(0-多)
//使用可变参数时,可以当做数组来使用,即nums可以当做数组
//遍历nums求和
public int sum(int... nums){
int res = 0;
for(int i = 0; i < nums.length; i++){
res += nums[i];
}
return res
}
细节:可变参数的实参可以是0或任意多个
可变参数的实参可以是数组
可变参数的本质就是数组
可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
一个形参列表中只能有一个可变参数
四、作用域
全局变量(属性):作用域为整个类体(如 cat 类),可以不赋值直接使用,因为有默认值,可以被本类使用,或其他类使用(通过对象调用),可以加修饰符
局部变量:除了属性之外的变量,一般指在成员方法中定义的变量,作用域为定义它的代码块中,必须赋值后才能使用,因为没有默认值,只能在本类中对应的方法中使用,不可以加修饰符
属性和局部变量可以重名,访问遵守就近原则
在同一个作用域中,比如在同一个成员方法中,两个局部变量不能重名
属性的生命周期比较长,伴随对象的创建而创建,伴随对象的销毁而销毁
局部变量的生命周期比较短,伴随它的代码块执行而创建,伴随代码块的结束而销毁
五、构造器(构造方法)
是类的一种特殊方法,主要作用是完成对新对象的初始化
基本语法:[修饰符] 方法名(形参列表){ 方法体; }
说明:构造器没有返回值
方法名和类名必须一样
构造器的调用由系统完成(在创建对象时,系统会自动的调用该类的构造器完成对对象的初始化)
一个类可以定义多个不同的构造器,即构造器重载
public class Constructor{
//编写一个main方法
public class void main(String[] args){
//new一个对象时,直接通过构造器指定名字和年龄
//构造器被调用时,对象已经存在,只是完成初始化
Person p1 = new Person("smith", 80) //第1个构造器
Person p2 = new Person("tom") //第2个构造器
}
}
class Person{
String name;
int age;
//第1个构造器
//没有返回值,也不能写void
//构造器名称和类名相同
//String pName, int pAge是构造器的形参列表,规则和成员方法一样
public Person(String pName, int pAge){
name = pName;
age = pAge;
}
//第2个构造器,只指定姓名,年龄默认为0
public Person(String pName){
name = pName;
}
//显示的定义一下默认无参构造器
Person(){
}
}
如果没有定义构造器,系统会自动给类生成一个默认无参构造器(也叫默认构造器):Person(){ } (javap反编译指令)
一旦定义了自己的构造器,默认的构造器就覆盖了,不能使用默认的无参构造器,除非显示定义一下
对象创建的流程分析
class Person{
int age = 90;
Sttring name;
Person(String n, int a){
name = n;
age = a;
}
}
Person p = new Person("小倩", 20);
1. 加载Person类信息,只会加载一次
2. 在堆中分配空间(地址)
3. 完成对象初始化:默认初始(age = 0, name = null)—>显示初始化(age = 90, name = null)—>构造器的初始化(age = 20, name = 小倩)
4. 把对象在堆中的地址返回给p(p是对象名,也可以理解成是对象的引用)
六、this
this代表当前对象(谁在调用这个构造器,this就指哪个对象)
class Person{
int age;
Sttring name;
Person(String name, int age){
this.name = name;
this.age = age;
}
}
细节:
this关键字可以用来访问本类的属性、方法、构造器
在成员方法中用this调用属性时,得到的结果是属性
但是如果在成员方法中直接调用相同名字的变量时,有可能是该方法内的局部变量
如果方法中没有局部变量,则在该方法中可以不适应this
this用于区分当前类的属性和局部变量
访问成员方法的语法:this.方法名(参数列表)
public class Detail{
public static void main(String[] args){
T t1 = new T();
t1.f2();
}
}
class T{
//访问成员方法的语法:this.方法名(参数列表)
public void f1(){
System.out.println("f1()方法..");
}
public void f2(){
System.out.println("f2()方法..");
//调用本类的f1
//第一种方式
f1();
//第二种方式
this.f1();
}
}
输出:
f2()方法..
f1()方法..
f1()方法..
访问构造器语法:this(参数列表)(注意:只能在构造器中使用,并且必须放在第一条语句)
public class Detail{
public static void main(String[] args){
T t2 = new T();
}
class T{
//访问构造器的语法:this(参数列表),只能在构造器中使用
public T(){
//在这里访问T(String name, int age),必须放在第一条语句
this("jack", 100);
System.out.println("T()构造器");
}
public T(String name, int age){
System.out.println("T(String name, int age)构造器");
}
}
输出:
T(String name, int age)构造器
T()构造器
this不能在类定义的外部使用,只能在类定义的方法中使用
new Test() 是匿名对象,地址没有返回,因此该对象只能使用一次
new Test().count() 创建好匿名对象后,就调用count()
七、访问修饰符
四种访问修饰符,用于控制方法和属性(成员变量)的访问权限
1. 公开级别:public ,对外公开
2. 受保护级别:protected ,对子类和同一个包中的类公开
3. 默认级别:没有符号,向同一个包中的类公开
4. 私有级别:private ,只有类本身可以访问,不对外公开
修饰符可以修饰类中的属性、成员方法以及类
只有默认的和 public 才能修饰类