Thinking in java(三)

1.局部变量和成员变量:
局部变量和成员变量的区别:
1、从定义上来讲:
局部变量定义在函数中。
成员变量定义在类中。
2、从内存存储上来讲:
局部变量随着函数的运行会在栈内存中出现,局部变量存储在栈内存中。
成员变量会随着对象的出现在堆中存在,成员变量存储在堆内存中。
3、从初始值上来讲:
局部变量在定义时需要指定初始值(局部变量没有默认值),只有初始化之后才能使用。
成员变量可以不用初始化,有默认值。
4、从存活时间上来讲(生命周期)
局部变量是随着函数的进栈在函数所属的栈内存中存在,随着函数的出栈就消失。
成员变量是随着对象的出现在堆中出现。随着对象的消失而消失。

2.面向对象语言的三大特性:封装,继承和多态。
a) 封装:对事物进行包装;如一个类中成员变量全部私有,对外提供getXxxx函数或者setXxxx函数
i. 可以隐藏事物的细节;
ii. 封装可以提高程序中代码的复用性。(比如函数和类)

3.构造方法:是在创建对象时(使用new时),会自动调用的函数。
构造函数定义的细节:
1、构造函数是用来创建对象的,它不需要书写返回值类型。(no void)
2、构造函数的名字要求必须和当前的类名一致。因此构造函数的名称书写和类名一致。
3、参数列表,可以和一般函数的参数列表一样。

4.构造和一般函数异同:
a) 执行时间不同:
i. 构造函数在创建对象的过程中执行;
ii. 一般函数的执行:本类中随用随调;其他类中,通过对象的实例调用
b) 调用次数不同:
i. 构造只有在创建对象执行;只调用一次
ii. 一般函数随时都可以被调用;
c) 互相调用问题:
i. 构造函数可以调用一般函数,一般函数不可以调用构造函数;
ii. 构造函数调用其他构造函数用super;

5.This关键字
this的应用:
1、this是用来记录当前调用这个函数的这个对象。
2、this可以在构造函数中完成调用其他的构造函数。格式 this( 实际参数 );
3、this可以区分成员变量和局部变量。格式:this.成员变量名 ;**

a) 在Java中只要是通过名称调用函数,那么调用的都是一般函数,构造函数之间不能通过函数名调用。
b) this调用其它构造函数的格式: this(参数列表); //相当于 构造函数(参数列表)
c) this调用构造函数注意:
i. 不能嵌套调用;
ii. This调用语句,必须放在第一句;
小结:
构造函数有两种调用方式:(没有对象就没有this)
1, 在new创建对象时,自动调用相应构造函数
2,使用this(参数列表)来调用其它构造函数。(前提:需要先有一个对象被创建,在被创建的对象自动调用构造函数时,在这个被调用的构造函数中才可以使用this)

6.statis静态关键字
a) Statis修饰成员函数成为静态成员函数;
静态成员函数使用注意事项:
i. 静态函数也称类函数,通过类去调用;
ii. Statis可以修饰成员变量和成员函数,不能修饰构造函数
iii. 静态函数在类加载的过程中就被加载了,可以直接调用;非静态函数需要在类加载结束后,创建对象后才能调用;
iv. 静态函数中不能使用非静态函数,非静态函数中可以使用静态函数;非静态函数需要在类加载结束后,那时候静态函数已经加载完成了;
v. 静态函数中不能使用this和super关键字;静态函数不存在对象的概念;而this表示调用函数的对象;矛盾。
b) 静态成员变量:静态方法区中;

7.静态成员变量和非静态成员变量的区别:市区出生
出现时间不同;存在区域不同;初始化时间不同;生命周期不同
1、它们在内存中出现的时间不同:
静态成员变量:它是在加载当前这个类的时候,就在方法区的静态区中存在。
非静态成员变量:当创建这个类的对象的时候,随着对象的产生在堆中出现。
2、它们所在的内存区域不同:
静态成员变量:在方法区的静态区中。
非静态成员变量:堆内存中。
3、它们的初始化时间不同:
静态成员变量:在类加载的时候就会初始化,类加载完成,变量已经初始化结束。
非静态成员变量:它是在对象的创建过程中被初始化。
4、它们的生命周期不同:
静态成员变量:它随着类的加载就在方法区的静态区中一直存在。直到jvm虚拟机关闭,类从方法区消失,静态成员变量才会消失。
非静态成员变量:它是随着对象的产生而存在,随着对象的消失就消失

8.代码块
a) 静态代码块:(仅执行一次,对类做初始化)用他完成程序启动的时候数据的初始化动作。类中所有的静态成员变量显示赋值结束之后,静态代码块才会运行
b) 构造代码块:super();成员变量显示初始化;构造代码块执行
c) 局部代码块: 限制变量的作用范围

9.定义class的时候成员位置上能够写什么?
a) 成员变量;成员函数;构造代码块;构造函数;静态代码块

10.类加载的过程:(TODO:JVM)
a) 启动jvm,加载程序中需要的class文件;
b) 在加载class文件时;所有静态内容都会被加载到方法区的静态区;
c) 加载完成后,给类中的所有静态成员变量默认初始化;
d) 默认初始化完车后,开始给这些静态成员变量显示赋值;
e) 显示赋值结束后;开始运行类中的静态代码块;
f) 已上步骤完成后,才表明类被加载完成;

11.
对象的创建过程:
1、使用new关键字创建对象,在堆给对象分配内存空间。
2、给对象所属类中的所有非静态成员变量分配空间并进行默认的初始化。
3、执行和new对象时传递参数一致的构造函数。
4、执行构造函数的的过程中有隐式的三步:
4.1、执行super() 语句,找父类的空参数构造函数
4.2、给非静态成员变量进行显示赋值。
4.3、运行构造代码块
4.4、构造函数中的自己写的代码执行。
5、构造函数执行完成,对象创建结束。
可见:代码块的执行在变量的赋值之后。

12.继承
a) Java支持单继承,多实现,支持多重继承;
b) 子类继承父类之后,就可以使用父类中的成员,private修饰的成员(成员函数、成员变量)不能被子类继承。
c) super有两个作用:
1) super.父类成员(变量,函数)
2) super(参数); 访问父类的构造函数
d) this和super的区别:
1) this表示的本类中的成员,super表示父类中的成员。
2) 在Java中,this是一个引用变量,它中保存的是当前调用这个函数的那个对象的内存地址。
super仅仅表示的父类的内存空间。但不是父类的对象。super仅仅只是一个标记,标记哪个是父类。
3) this表示子类对象在堆中开辟的整个空间,而super标记的是子类对象开辟空间中的父类所占的空间。
e) 继承中成员函数:
函数重写(复写):
在子父类中,出现了一模一样的函数。一模一样:要求函数的返回值类型、函数名、函数的参数列表必须相同。子类在复写父类的函数时,子类的方法访问权限,必须大于等于父类的权限。

13.
1、为什么任何一个类(不包含Object)的构造函数中需要一个隐式的super() 语句?
因为任何子类继承父类后,都会继承父类的成员变量,这时在创建子类对象的,会在子类的对象空间中分配出空间存储父类的成员变量。而父类的成员变量初始化动作必须由父类的自己的构造函数完成。所以在任何类的构造函数中有一个隐式的super()语句。
2、由1也可知,如果一个函数中的全部构造函数都私有的话,那么他不会再子类;
3、this调用构造函数可以和super调用父类构造函数共存吗?不能,他们俩调用构造函数都需要在构造函数的第一行;

14.final:
a) 被final修饰的内容都是最终内容,不能被修改;
b) 被final修饰的函数不能被子类复写;
c) 被final修饰的变量,成为常量;它空间中存放的数据永远都不能被修改;
d) 被final修饰的类,不能被继承。

15.抽象类
a) 拥有抽象方法的类一定是抽象类;当一个类继承某个抽象类,这时这个类要把这个抽象类中的所有抽象方法全部复写。
b) 抽象类一定是个类,类中肯定就会有构造函数。抽象类不能创建对象的原因是抽象类中有抽象函数,如果我们可以直接创建抽象类的对象,那么就可以使用这个对象调用那个抽象函数,而抽象函数是没有函数体的函数,调用函数的最终目的是需要函数体的执行,完成我们想要的结果(调用抽象函数是没有意义的)。
c) 抽象类一定是父类;不一定是顶级父类;抽象类也是一个类,所以也可以继承其他类;
d) 抽象关键字不能和哪些关键字共存?Private ,static ,final;

16.接口
a) 接口中的成员变量修饰:
public static final ,这三个修饰符 可以省略不写。如果在代码中不写,那么编译器编译源文件生成类文件的时候会在变量前面默认加上以上三个修饰符。
接口中的变量,都是常量。因此接口中的变量名一般都会全部大写。

b) 接口中的成员函数:
public abstract 返回值类型 函数名( 参数列表 );
注意:接口中的函数也是抽象的,没有函数体。
public abstract 可以省略,但是建议可以省略 abstract ,不要省略 public。
如果在代码中不写,那么编译器编译源文件生成类文件的时候会在函数返回值类型前面默认加上以上两个修饰符。

17.多态
多态中的类型转换有两种:
1)向上转型(隐式的类型提升) 父引用指向子类对象 例:Animal an = new Dog();
2)向下转型(强制类型转换或者把父类类型转成子类类型) 把父引用强制转为子类引用 例:Dog d=(Dog) an;
强制类型转换格式:子类类型 子类引用名=(子类类型)父类引用名;
向下转型有风险,用的时候最好判断来规避:instanceof

19.
在多态中,永远只会使用父类中的成员变量,不会使用子类中成员变量。
多态时,子父类中存在一模一样的成员方法时,编译时以等号左边作为参考,运行时是以等号右边作为参考。Father f=new Child();
总结:成员变量(非静态和静态)和静态成员函数,编译运行都看左边(父类中的)。只有非静态成员函数,编译看父类,运行看子类对象。

(两个定理 来加深理解:
1.当把子类对象当做父类对象来看时,就只能调用父类中原有定义的属性和方法,子类自己扩展的属性和方法就不能调用了;
比如将猫看做一只宠物,不知道他是猫;只知道他是宠物,并且具有宠物的一些属性和方法,这个时候就不会去调用他特有的方法;也不知道他有什么特有的方法.客观存在并没有左右主观认识.
2.当把子类对象当做父类对象来看时,如果子类重写了父类中的方法,则调用该方法时调用的是子类重写后的方法.
定理二与定理一似乎有所冲突,但其实定理二调用的是他特有的方法,所以并不冲突,好比宠物都具有吃饭的方法,虽然把猫当宠物,但是他并不会因为我们把它当做宠物而不吃鱼改去吃草.主观认识并不能影响客观存在.

原文地址:https://www.cnblogs.com/DiZhang/p/12545096.html