JAVA学习(3)

1.对象与对象引用的区别

对象与对象引用的区别
e.g.

public class Example{

    public Example{
    }
} 
Example example=new Example();

1.new 在堆空间创造了Example对象
2.()指调用默认的构造函数
3.Example example创建了类引用变量,存储在栈空间中
4.=使对象引用指向刚创建的那个对象
一个引用可以指向多个对象,而一个对象可以被多个引用所指。

2.对象作为参数传递的特点

举例说明:
e.g.

把StringBuffer对象作为参数传递到change函数。

public class test {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("Hello ");
        System.out.println("before change, sb is "+sb.toString());
        change(sb);
        System.out.println("after change, sb is "+sb.toString());
    }
    public static void change(StringBuffer stringBuffer){
        stringBuffer.append("world !");
    }
}

从输出结果中我们可以发现,sb所指向的对象的值被改变了,但不足以证明传递的是引用。
再看一个例子。
e.g.

public class test {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("Hello ");
        System.out.println("before change, sb is "+sb.toString());
        change(sb);
        System.out.println("after change, sb is "+sb.toString());
    }
    public static void change(StringBuffer stringBuffer){
        stringBuffer = new StringBuffer("Hi ");
        stringBuffer.append("world !");
    }
}

原对象的值并没有被改变,为什么在Java中,当对象作为参数传递时,有的时候实参被改变了,而有的时候实参并未被改变呢?下面让我们来分析一下其中的原因:
当执行StringBuffer sb = new StringBuffer(“Hello “)时,我们创建了一个指向新建对象“new StringBuffer(“Hello “)”的引用“sb”。
在例1中,当我们调用change函数后,实际上,形参stringBuffer也指向了实参sb所指向的对象。

那么当我们执行stringBuffer.append(“world !”)后,便通过对象的引用“stringBuffer”修改了对象的值,使之变成了“Hello world !”。
但是,在例2中的change函数中,我们又新建了一个对象“new StringBuffer(“Hi “)”(这实际上在内存中开辟了一块在原对象地址之外的新区域),这让形参stringBuffer实际指向了这个新建的对象,并将新对象的值设置为“Hi world !”。

综上所述,我们可以得出结论:在Java中,当对象作为参数传递时,实际上传递的是一份“引用的拷贝”。

3.对象的初始化顺序

e.g.

public class Father {

  static final String STATIC_FIELD_01 = getFatherField("STATIC_FIELD_01");

  private String field01 = getMemberFatherField("field01");

  public Father() {
    System.out.println("父类构造方法!");
  }

  static {
    System.out.println("父类静态代码块!");
  }

  static final String STATIC_FIELD_02 = getFatherField("STATIC_FIELD_02");

  static String getFatherField(String str) {
    System.out.println("父类静态成员变量初始化-" + str);
    return str;
  }

  {
    System.out.println("父类代码块!");
  }

  private String field02 = getMemberFatherField("field01");

  String getMemberFatherField(String str) {
    System.out.println("父类静态成员变量初始化-" + str);
    return str;
  }

  static class Son extends Father {

  static final String STATIC_FIELD_01 = getSonField("STATIC_FIELD_01");

    private String field01 = getMemberSonField("field01");

    public Son() {
      System.out.println("子类构造方法!");
    }

    static {
      System.out.println("子类静态代码块!");
    }

    static final String STATIC_FIELD_02 = getSonField("STATIC_FIELD_02");

    static String getSonField(String str) {
      System.out.println("子类静态成员变量初始化-" + str);
      return str;
    }

    {
      System.out.println("子类代码块!");
    }

    private String field02 = getMemberSonField("field02");

    String getMemberSonField(String str) {
      System.out.println("子类成员变量初始化-" + str);
      return str;
    }


  }

  public static void main(String[] args) {
    new Son();
  }
}

输出:
父类静态成员变量初始化-STATIC_FIELD_01
父类静态代码块!
父类静态成员变量初始化-STATIC_FIELD_02
子类静态成员变量初始化-STATIC_FIELD_01
子类静态代码块!
子类静态成员变量初始化-STATIC_FIELD_02
父类静态成员变量初始化-field01
父类代码块!
父类静态成员变量初始化-field01
父类构造方法!
子类成员变量初始化-field01
子类代码块!
子类成员变量初始化-field02
子类构造方法!

结论:
初始化父类的静态代码—>初始化子类的静态代码–>初始化父类的非静态代码—>初始化父类构造函数—>初始化子类非静态代码—>初始化子类构造函数
static 关键字修饰的(如:类变量[静态变量]、静态代码块)将在类被初始化创建实例对象之前被初始化,而且是按顺序从上到下依次被执行;
没有 static 关键字修饰的(如:实例变量[非静态变量]、非静态代码块)初始化实际上是会被提取到类的构造器中被执行的,但是会比类构造器中的代码块优先执行到,其也是按顺序从上到下依次被执行。

4.类的static字段和非static字段区别

关于static和非static变量的区别

static 修饰的变量称为类变量或全局变量或成员变量,在类被加载的时候成员变量即被初始化,与类关联,只要类存在,static变量就存在。非static修饰的成员变量是在对象new出来的时候划分存储空间,是与具体的对象绑定的,该成员变量仅为当前对象所拥有的。

static修饰的变量在加载的时候先于main方法加载在内存中的数据共享区-------方法区,而非static的变量在加载的时候,是要创建变量才加载在堆内存中的。

一个static变量单独划分一块存储空间,不与具体的对象绑定在一起,该存储空间被类的各个对象所共享。static变量值在方法区加载一次,而非static在创建对象时会加载很多次。每次创建都会拷贝一份。

对象在引用成员变量是直接通过类名.变量名调用,对象在引用实例变量时只能通过对象名.变量名调用。

在类中调用成员变量时直接调用或者以类名.变量名方式调用,实例变量则用this或者直接调用。

关于static方法和非static方法的区别

static修饰的方法也和static一样。先于main方法被加载到方法区,以便共享使用。

静态的static方法中不能使用this或者super关键字,因为static方法是先于对象创建之前就已经加载的方法,是属于类的方法,而this和super指向的是本类的对象或者父类的对象,非静态的方法是属于对象的,方法里可以用this和super。

static方法可以用对象.方法名来调用,也可以用类名.方法名来调用。而非静态的方法只能创建对象后时调用。

static方法是加载一次,被所有的对象所共享。而非静态方法是有多少个对象就拷贝多少次,每个对象只能调用自己的拷贝的方法。

对象调用非静态的方法时,不考虑线程安全性的问题,而调用静态方法时,要考虑安全性的问题。因为静态方法只有一份。而对象的方法是自己有自己的。

同一个类中,静态方法中只能访问类中的静态成员。而非静态方法可以访问非静态的方法(使用类名调用,或者创创建本类的对象调用)。

5.Java中的final关键字所起的作用

1、final修饰类中的属性或者变量
无论属性是基本类型还是引用类型,final所起的作用都是变量里面存放的“值”不能变。
这个值,对于基本类型来说,变量里面放的就是实实在在的值,如1,“abc”等。

而引用类型变量里面放的是个地址,所以用final修饰引用类型变量指的是它里面的地址不能变,并不是说这个地址所指向的对象或数组的内容不可以变,这个一定要注意。

例如:类中有一个属性是final Person p=new Person(“name”); 那么你不能对p进行重新赋值,但是可以改变p里面属性的值,p.setName(‘newName’);

final修饰属性,声明变量时可以不赋值,而且一旦赋值就不能被修改了。对final属性可以在三个地方赋值:声明时、初始化块中、构造方法中。总之一定要赋值。
2、final修饰类中的方法
作用:可以被继承,但继承后不能被重写

3、final修饰类
作用:类不可以被继承。

6.Java中float[10] arr; 语句正确吗?

不正确。
系统无法识别该语句给arr数组分配内存空间。

7.java数组元素类型为基本数据类型和引用类型有什么不同?

数组元素的值直接存储在对应的数组元素中,因此,初始化数组时,先为该数组分配内存空间,然后直接将数组元素的值存入对应数组元素中。
引用类型数组的数组元素是引用,因此情况变得更加复杂:每个数组元素里存储的还是引用,它指向另一块内存,这块内存里存储了有效数据。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值