JAVA学习(3)

    科技2022-07-29  108

    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数组元素类型为基本数据类型和引用类型有什么不同?

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

    Processed: 0.011, SQL: 8