文章目录
1、方法调用时内存结构特点
方法不调用不执行,调用一次执行一次,每次调用会在栈中有一个入栈动作,即给当前方法开辟一块独立的内存区域,用于存储当前方法的局部变量的值,当方法执行结束后,会释放该内存,称为出栈,如果方法有返回值,就会把结果返回调用处,如果没有返回值,就直接结束,回到调用处继续执行下一条指令。
栈结构:先进后出,后进先出。
小结:我们只需知道,方法声明时,会在栈里生成一个空间,然后实例化(new)时在堆内生成空间,然后我们调用就直接在堆内调取使用。
2、基础类型传参和引用类型传参的内存分析
基本类型作为形参传递——值传递
基本类型作为形参传递的时候,传递的是值,在函数体内修改基本类型的值是不会改变原本的函数体外的变量的值。
引用类型作为形参传递——本质也是值传递
引用类型在作为形参传递的时候,很多人认为这是一个地址传递,因为引用类型在传入函数体后,我们操作引用的对象,对象的数据是改变了的,因此很多人认为这是一个地址传递,但引用和地址存在着本质的区别。我们来看下面这个例子。
图形结构
创建对象发生的事,创建两个栈区内存,两个堆区内存,建立了映射关系
然后我们来看传入方法体内发生了什么,很明显,传入的是引用,引用本身存的是一个堆区地址。
再看方法体内发生了什么,我们通过new创建了新的对象,这个对象命名为C,我们把方法体内A的引用变为C,所以此时它指向的是C的数据区,然后,我们通过传入的B的引用修改了堆区的内容
接下来方法体结束后的操作:我们可以看到,在函数体内将Node A的内容修改为指向C,方法体结束后,并没有使栈区中的Node A指向C,但是,我们通过传入的B的引用,修改了B中数据,数据在堆区中被修改了,方法体结束后B中的数据已经修改为了D。
由此我们可以看出,Java中的引用传递,本质上还是值传递,只不过这个时候我们传递的是引用的值而已(也可以理解为对应的堆区的数据的地址) 因此我们在方法体结束后,我们并不能修改引用,但是在方法体内我们可以通过传入的引用去修改堆区内的内容。
小结:我们只需要了解一下传入的参数最后会运行一个什么样的结果,目前阶段来说
会用就行
,至于内存的一个传递机制,可进行一个了解性内容,主要是方便我们理解内容。
3、静态
1、静态的属性的特点
1、语法格式
有static修饰的成员变量就是静态变量。
【修饰符】 class 类{
【其他修饰符】 static 数据类型 静态变量名;
}
2、静态变量的特点
- 静态变量的默认值规则和实例变量一样。
- 静态变量值是所有对象共享。
- 静态变量的值存储在方法区。
- 静态变量在本类中,可以在任意方法、代码块、构造器中直接使用。
- 如果权限修饰符允许,在其他类中可以通过“类名.静态变量”直接访问,也可以通过“对象.静态变量”的方式访问(但是更推荐使用类名.静态变量的方式)。
- 静态变量的get/set方法也静态的,当局部变量与静态变量重名时,使用“类名.静态变量”进行区分。
分类 | 数据类型 | 默认值 |
---|---|---|
基本类型 | 整数(byte,short,int,long) | 0 |
浮点数(float,double) | 0.0 | |
字符(char) | ‘\u0000’ | |
布尔(boolean) | false | |
数据类型 | 默认值 | |
引用类型 | 数组,类,接口 | null |
静态类变量和非静态实例变量、局部变量
- 静态类变量(简称静态变量):存储在方法区,有默认值,所有对象共享,生命周期和类相同,还可以有权限修饰符、final等其他修饰符
- 非静态实例变量(简称实例变量):存储在堆中,有默认值,每一个对象独立,生命周期每一个对象也独立,还可以有权限修饰符、final等其他修饰符
- 局部变量:存储在栈中,没有默认值,每一次方法调用都是独立的,有作用域,只能有final修饰,没有其他修饰符
2、静态的方法
1、语法格式
有static修饰的成员方法就是静态方法。
【修饰符】 class 类{
【其他修饰符】 static 返回值类型 方法名(形参列表){
方法体
}
}
2、静态方法的特点
- 静态方法在本类的任意方法、代码块、构造器中都可以直接被调用。
- 只要权限修饰符允许,静态方法在其他类中可以通过“类名.静态方法“的方式调用。也可以通过”对象.静态方法“的方式调用(但是更推荐使用类名.静态方法的方式)。
- 静态方法可以被子类继承,但不能被子类重写。
- 静态方法的调用都只看编译时类型。
小结:小结:关键字【static】可以给类或者方法进行一个静态化,静态的方法访问只能访问静态的方法,不能直接访问普通类、方法。而普通类则可以直接访问静态的方法或者类。
4、变长参数组
在JDK1.5之后,当定义一个方法时,形参的类型可以确定,但是形参的个数不确定,那么可以考虑使用可变参数。可变参数的格式:
【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型... 形参名){ }
可变参数的特点和要求:
(1)一个方法最多只能有一个可变参数
(2)如果一个方法包含可变参数,那么可变参数必须是形参列表的最后一个
(3)在声明它的方法中,可变参数当成数组使用
(4)其实这个书写“≈”
【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型[] 形参名){ }
只是后面这种定义,在调用时必须传递数组,而前者更灵活,既可以传递数组,又可以直接传递数组的元素,这样更灵活了。
小结:变长参数组,在参数方法中有且只有一个,且需要保持在最后面的参数
5、方法重载
- 方法重载:指在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返回值类型无关。
- 参数列表:数据类型个数不同,数据类型不同(按理来说数据类型顺序不同也可以,但是很少见,也不推荐,逻辑上容易有歧义)。
- 重载方法调用:JVM通过方法的参数列表,调用匹配的方法。
- 先找个数、类型最匹配的
- 再找个数和类型可以兼容的,如果同时多个方法可以兼容将会报错
小结:方法重载体现在一个参数上,参数传入什么类型的值,我们就调用什么类型的方法,比如==System.out.println()==括号内放字符串,则识别字符串,数字则识别数字
6、对象数组
数组是用来存储一组数据的容器,一组基本数据类型的数据可以用数组装,那么一组对象也可以使用数组来装。
即数组的元素可以是基本数据类型,也可以是引用数据类型。当元素是引用数据类型是,我们称为对象数组。
注意:对象数组,首先要创建数组对象本身,即确定数组的长度,然后再创建每一个元素对象,如果不创建,数组的元素的默认值就是null,所以很容易出现空指针异常NullPointerException。
小结:典型的例子就是我们的String引用类型然后调用在我们的参数中。
7、构造器
我们发现我们new完对象时,所有成员变量都是默认值,如果我们需要赋别的值,需要挨个为它们再赋值,太麻烦了。我们能不能在new对象时,直接为当前对象的某个或所有成员变量直接赋值呢。
可以,Java给我们提供了构造器(Constructor)。
1、构造器的作用
new对象,并在new对象的时候为实例变量赋值。
2、构造器的语法格式
构造器又称为构造方法,那是因为它长的很像方法。但是和方法还是有所区别的。
【修饰符】 class 类名{
【修饰符】 构造器名(){
// 实例初始化代码
}
【修饰符】 构造器名(参数列表){
// 实例初始化代码
}
}
注意事项:
- 构造器名必须与它所在的类名必须相同。
- 它没有返回值,所以不需要返回值类型,甚至不需要void
- 如果你不提供构造器,系统会给出无参数构造器,并且该构造器的修饰符默认与类的修饰符相同
- 如果你提供了构造器,系统将不再提供无参数构造器,除非你自己定义。
- 构造器是可以重载的,既可以定义参数,也可以不定义参数。
- 构造器的修饰符只能是权限修饰符,不能被其他任何修饰
同一个类中的构造器互相调用
- this():调用本类的无参构造
- this(实参列表):调用本类的有参构造
- this()和this(实参列表)只能出现在构造器首行
- 不能出现递归调用
小结:一般需要生成两个构造器,一个是无参的构造器,一个是有参的构造器。
总结:今天所了解的是关于一个面向对象。主要理解了形参,重载,以及我们的对象数组与构造器。
构造器:有助于我们在实例化对象时调用对象方法是传入参数,大大减少我们代码的冗余;
重载则是告诉我们对于一个形参的类型使用。
每日金句:
有志者,事竟成,破釜沉舟,百二秦关终属楚;
苦心人,天不负,卧薪尝胆,三千越甲可吞吴.