对象是类的实例
一个对象至少占据16字节,其中包含12字节的对象头信息。除此以外,还有实例数据,对齐填充字节
对象引用相当于C++中的指针,它指向是堆内存中的对象实例
一个对象引用变量均占据4字节空间
假如在某个方法中,有如下语句:
Student st = new Student();
new Student(); 将对象分配在堆heap上,创建了对象
Student st; 声明了对象引用st,st为局部变量分配在栈stack上
st = new Student(); 赋值操作将新创建的Student对象的首地址赋给对象引用st,使st指向实际对象,可以通过st操纵该对象
对象作为参数传递的特点直接上代码说明:
package com.company;
class node{
int num=1;
int cnt=1;
}
public class Main{
public static void f(int s){
s++;
System.out.println("i="+s);
}
public static void f(String s){
s+="yfffy";
System.out.println("s="+s);
}
public static void f(node s){
s.num=9;
s.cnt=9;
System.out.println("n.num="+s.num);
System.out.println("n.cnt="+s.cnt);
}
public static void main(String[] args){
node n=new node();
int i=1;
String s="wpppf";
System.out.println("s="+s);
System.out.println("i="+i);
System.out.println("n.num="+n.num);
System.out.println("n.cnt="+n.cnt);
f(n);
f(i);
f(s);
System.out.println("s="+s);
System.out.println("i="+i);
System.out.println("n.num="+n.num);
System.out.println("n.cnt="+n.cnt);
}
}
上图代码输出为:
结论:java中一般对象(包括数组)作为参数是引用传递,但是字符串(String)是值传递(划重点);基本类型变量当做值传递。 对象初始化顺序s=wpppf
i=1
n.num=1
n.cnt=1
n.num=9
n.cnt=9
i=2
s=wpppfyfffy
s=wpppf
i=1
n.num=9
n.cnt=9
创建对象时的初始化顺序(无继承):
- 1.对静态代码进行初始化
- 2.对非静态代码进行初始化
- 3.调用构造函数初始化
上代码:
package com.company;
class node{
public node(String s){
System.out.println(s);
}
}
class Test {
node n2 = new node("n2成员初始化");
static node n1 = new node("静态对象n1初始化");
static {
System.out.println("static块执行");
n1 = new node("静态块内初始化n1成员变量");
}
public Test(){
System.out.println("Test默认构造函数被调用");
}
}
public class Main{
public static void main(String[] args){
Test a=new Test();
}
}
代码输出:
静态对象n1初始化——对静态代码进行初始化
static块执行——对静态代码进行初始化
静态块内初始化n1成员变量——对静态代码进行初始化
n2成员初始化——对非静态代码进行初始化
Test默认构造函数被调用——调用构造函数初始化
有继承情况下:
先初始化父类的静态代码—>初始化子类的静态代码–>初始化父类的非静态代码—>初始化父类构造函数—>初始化子类非静态代码—>初始化子类构造函数
static字段与非static字段&什么场景应该使用static修饰符?static修饰符修饰的变量不属于任何一个类的具体对象,它被保存在类的内存区的公共储存单元中。因此,一个类的任何对象访问它的时候得到的数值都是相同的,方位的方式为“类名.域名”,也可以通过对象引用来访问。
static方法内部的代码,只能访问类中的static属性或方法(因为他们属于对象)。但非static方法(对象方法)可以访问static属性或方法。
静态代码块:在一个类当中可以有不包含在任何方法体当中的静态代码块,当类被装载的时候(即代码编译的时候),静态代码块执行一次且只执行一次。静态代码块一般用来对类中定义属性的初始化。
例如:
class node{
int num;
static{
num=3;
System.out.println(“num=”+num);
}
}
此外,main方法是特殊的静态方法。
那么什么时候使用static方法呢?
当需要所有对象共享的数据时,就应该使用static修饰。例如,对于一个类,需要有变量记录该类的对象个数,这时候就应该把记录对象个数的变量用static修饰。
class node{
String s;
static cnt;
public node(){
cnt++;
}
public node(String t){
s=t;
cnt++;
}
}
final修饰符
final修饰符可以修饰变量、方法和类
final变量:
当final修饰变量的时候这个变量就会变成常量,能被显式地初始化并且只能初始化一次。被声明为final的对象的引用不能指向不同的对象。但是final对象里的数据可以被改变。也就是说final对象的引用不能改变,但是里面的值可以改变。
final int x=9; x=2;//修改final变量出错
final方法:
类中的final方法可以被子类继承,但是不能被子类重写、修改。
声明final方法的主要目的是防止该方法的内容被修改。
class node{
int num;
public final void fun(){
System.out.println("abc");
}
}
class nnode extends node{
int sum;
public void fun(){//重写final方法出错
System.out.println("def");
}
}
final类:
final类不能被继承,没有类能够继承final类的任何特性,这意味着这个类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改和扩展。
final class node{
int num;
}
class nnode extends node{//继承final类出错
int sum;
}
float[10] arr; 语句正确么?
首先,这肯定是不正确的。
在声明数组的引用时,不能在[]内指定数组大小。
正确的声明与定义数组的方式如下:
int[] array1 = {1,2,3,4,5};
int[] array2 = new int[5];
int[] array3 = new int[]{1,2,3,4,5};
Java数组元素类型为基本类型和引用类型时,有什么不同?
数组元素为基本类型时,数组中储存的即为对应数据类型的值。
数组元素为引用类型时,数组中储存的是引用,指向其他内存空间,默认值为null。
public class Main {
public static void main(String[] args) {
int arr1[] = new int[10];
for(int i=0; i < arr1.length; i++){
System.out.printf("%d ",arr1[i]);
}
for(int i=0; i < arr1.length; i++){
arr1[i] = i;
System.out.printf("%d ",arr1[i]);
}
String arr2[] = new String[10];
for(int i=0; i < arr2.length; i++){
System.out.printf("%s ",arr2[i]);
}
}
}
输出:
0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 null null null null null null null null null null



