欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > > 文章正文

5.面向对象(上),面向对象

来源: javaer 分享于  点击 11542 次 点评:150

5.面向对象(上),面向对象


简要:

1.Java支持面向对象的三大特征:封装,继承,多态

封装:成员变量私有化,通过提供getter,setter方法来访问;

继承;子类能拥有父类的成员变量以及方法,注意,如果用private修饰,则不能继承;

多态;有继承,有重写,有父类引用指向子类对象,就会产生多态;

2.如果多个构造器里面包含了相同的初始化代码,可以放到普通初始化块里面,初始化块总在构造器执行之前被调用;


1.类和对象

1).定义类

a.定义类:

I.类的修饰符:public,default,final,abstract;

II.如果为一个类提供了构造器,系统将不再为该类提供构造器,所以自定义构造器时,最好显示的提供一个默认无参构造器;

b.定义成员变量:

I.成员变量的修饰符:private,protected,default,public,static,final;

c.定义方法;

I.方法的修饰符:private,protected,default,public,static,final,abstract,其中abstract和final只能出现其中之一;

II.static修饰的成员表面他属于这个类本身,而不属于该类的单个实例;

III.静态成员不能直接访问非静态成员;

注意:static的真正作用,是用于区分成员变量,方法,内部类,初始化块,这四种成员到底属于类本身还是属于实例;

d.定义构造器:

I.构造器的修饰符:private,protected,default,public;

2).对象的产生和引用

a.创建对象的四种方式:new,反射,反序列化,克隆,但是创建对象的根本方式还是通过构造器;

3).对象,应用和指针

a.Java程序不允许直接访问堆内存中的对象,只能通过该对象的引用操作该对象;

4).对象的this引用

a.this关键字总是指向调用该方法的对象;根据this出现位置的不同,this作为对象的默认引用有两种情形:

I.构造器中引用改构造器正在初始化的对象

II.在方法中引用调用该方法的对象;

注意:this关键字的最大作用就是让类中一个方法,访问该类里的另一个方法或实例变量;

2.方法详解

1).方法的所属性

a.同一个类的一个方法调用另外一个方法时,如果被调方法是普通方法,默认使用this作为调用者;如果被调用方法是静态方法,默认使用类作为调用者;

2).方法的参数传递机制

a.调用方法时,实际传给形参 参数值也被称为实参;

b.Java里方法的参数传递只有一种:值传递!所谓值传递,就是将实际参数值的副本(复制品)传入方法内,而参数本身不会受到任何影响;

c.引用类型的值传递实质是传的对象在内存中的地址;

一定要理解值传递,如果参数是基本数据类型,那没有任何问题,就是把值复制一下传过去,但是如果是引用类型的话,实际也是复制的值,只不过不死复制对象,而是复制引用变量的值,而引用变量的值一般就是对象在内存中的地址,这样实际操作的是同一个对象,就造成了一个错觉,引用类型不是指传递,而是传递的对象,这是错误的!

3).形参个数可变的方法

a.在最后一个形参的类型后增加三点(...);注意;只能放在形参列表的最后;

4).递归方法
5).方法重载

a.两同一不同:同一个类中方法名相同,参数列表不同;其他部分,并不care;

3.成员变量和局部变量

1).成员变量和局部变量

a.局部变量有三种:

I.形参:定义方法签名时定义的变量,形参的作用域在整个方法内有效;

II.方法局部变量:在方法体内定义的局部变量,作用域是从定义该变量的地方生效,到该方法结束时生效;

III.代码块局部变量:在代码块中定义的局部变量,作用域是从定义该变量的地方生效,到该代码块结束时失效;

注意:与成员变量不同的是,局部变量除了形参之外,都必须显示初始化;

当通过类或对象调用某个方法时,系统会在该方法栈区内为所有的形参分配内存空间,并将实参的值赋给对应的形参,这就完成了形参的初始化;

2).成员变量的初始化和内存中的运行机制

a.成员变量会自动初始化;

3).局部变量的初始化和内存中的运行机制

a.与成员变量不同,局部变量不属于任何类或实例,总是保存在其所在方法的栈内存中;

4).变量的使用规则

4.隐藏和封装

1).理解封装
2).使用访问控制符


private(当前类访问权限):只能在当前类的内部被访问;

default(包访问权限)

protected(子类访问权限):既可以被同一个包中的其他类访问,也可以被不同包中的子类访问,如果使用protected类修饰一个方法,通常是希望其子类来重写这个方法;

public(公共访问权限)


注意:对于外部类而言,只有两种访问控制权限:public和default,外部类不用使用private和protected修饰,因为外部类没有处于任何类的内部,也就没有其所在类的内部,所在类的子类两个范围,因此private,protected访问控制符对外部类没有意义;

如果某个类主要用做其他类的父类,该类里的大部分方法仅希望被其子类重写,而不想被外界直接调用,则应该使用peotected修饰这些方法;

3).package,import和import static

a.使用import可以省略包名;使用import static则可以连类名都省略;

4).Java的常用包

5.深入构造器

1).使用构造器执行初始化

a.构造器的最大作用就是在创建对象时执行初始化;创建一个对象时,系统为这个对象的实例变量进行默认初始化:

基本类型:0   布尔型:false   引用类型:null

b.一旦提供了自定义的构造器,系统就不再提供默认的构造器;

2).构造器重载

a.如果构造器B完全包含了构造器A,而已在B方法中调用方法A,为了在构造器B中调用构造器A,可以使用this类调用;

public Apple(String name,String color{
    this.name = name;
    this.color = color;
}
public Apple(String name,String color,String weight){
    this(name,color);
    this.weight = weight;
}
使用this调用另一个重载的构造器只能在构造器中使用,而且必须作为构造器执行提的第一条语句;

6.类的继承

1).继承的特点

a.继承:子类扩展了父类,将可以获得父类的全部成员变量和方法,如果是private修饰的,子类不能继承;

b.子类不能获得父类的构造器;

c.Java类只能有一个直接父类,可以由无限个间接父类;

2).重新父类的方法

a.重写:遵循"两同两小一大"原则:

方法名相同,形参相同;

子类方法返回值类型,子类方法抛出的异常类比父类小;

子类方法访问权限比父类大;

b.子类覆盖父类方法后,子类的对象无法访问父类中被覆盖的方法,但可以在子类方法中调用父类中被覆盖的方法;如果要在子类方法中调用父类中被覆盖的方法,可以这样:

super(被覆盖的是实例方法)   or    父类类名(被覆盖的是类方法)   作为调用者来调用父类中被覆盖的方法;

如果父类方法具有private访问权限,则该方法对其子类是隐藏的,因此其子类无法访问该方法;

方法的重载和方法重写区别:overload:override

重载主要发生在同一个类的多个同名方法之间     |     重写发生在子类和父类的同名方法之间

3).super限定

a.super用于限定该对象调用它从父类继承得到的实例变量或方法;

b.如果在构造器中使用super,则super用于限定该构造器初始化的是该对象从父类继承得到的实例变量,而不是该类自己的实例变量;

c.当系统创建了SubClass对象时,实际上会为SubClass对象分配两块内存,一块用于存储在SubClass类总定义的实例变量,一块用于存储从BaseClass类继承得到的实例变量;

d.在某个方法中访问名为a的变量,顺序为:

I.查找该方法中是否有名为a的局部变量;

II.查找当前类中是否包含名为a 的成员变量;

III.查找a直接父类中是否包含名为a的成员变量,一次上溯a的所有父类知道Object类,如果找不到,则出现编译错误;

e.如果被覆盖的是类变量,在子类的方法中则可以通过父类名作为调用者来访问被覆盖的类变量;

f.创建一个子类对象时,不仅为该类中定义的实例变量分配内存,也会为它从父类继承得到的所有实例变量分配内存,即使子类定义了与父类中同名的实例变量;eg:

系统创建一个对象时,该类有两个父类(一个直接父类A,一个间接父类B),假设A类中定义了2个实例变量,B类中定义了3个实例变量当前类中定义了2个实例变量,那么这个对象将会保存2+3+2个实例变量;

4).调用父类构造器

a.子类不会获得父类的构造器,但子类构造器可以调用父类构造器 初始化代码,类似构造器重载;

b.在一个构造器中调用另一个重载的构造器使用this调用来完成,在子类构造器中调用父类构造器使用super来完成;

public Sub(doubli size,String name,Sring color){
   //通过super调用父类构造器的初始化过程 
   super(size,name);
   this.color = color;
}

总结:使用super和this比较类似,区别在于super调用是其父类的构造器,this调用的是同一个类中重载的构造器,所以super调用也IXUS出现在子类构造器的第一行,this和super不会同时出现;

不管是否使用super调用父类构造器,子类构造器总会调用父类构造器一次,子类构造器调用父类构造器如下三种情况:

I.子类构造器执行体的第一行使用super显式调用父类构造器,系统根据super调用里传入的实参列表调用父类对应的构造器;

II.子类构造器执行体的第一行代码使用this显式调用本类中重载的构造器,系统将根据this调用里传入的实参列表调用本类中的另一个构造器,执行本类中另一个构造器时即会调用父类构造器;

III.子类构造器执行体中既没有super调用,也没有this调用,系统将会在执行子类构造器之前,隐式调用父类无参构造器;

不管哪种情况,当调用子类构造器来初始化子类对象时,父类构造器总会在子类构造器之前执行;不仅如此,执行父类构造器时,系统会再次上溯执行其父类构造器.....以此类推,创建任何对象,最先执行的总是Object类的构造器!

7.多态(有继承,有重写,有父类引用执行子类对象)

Java引用变量有两个类型:编译时类型,运行时类型

1).多态性

a.把一个子类对象直接赋给父类引用变量时:

BaseClass tt = new SubClass();
这个tt引用变量的编译时类型是BaseClass,运行时类型是SubClass,当运行时调用改引用变量的方法时,其方法行为总是表现出子类方法的行为,而不是父类的方法行为,就可能出现:相同类型的变量,调用同一个方法时呈现出多种不同的行为特征,这就是多态;

b.对象的实例不具有多态性;

c.引用变量在编译阶段只能调用其编译时类型所具有的方法,即:父类只能调用自己拥有的方法!所以,引用变量只能调用声明该变量时所用类里包含的方法;

d.通过引用变量来访问其包含的实例变量时,系统总是试图访问它编译时类型所定义的成员变量,而不是它允许时所定义的成员变量;

2).引用变量的强制类型转换

当进行强制类型转换时,注意:

a.基本类型之间的转换只能在数值类型之间进行;

b.引用类型之间的转换只能在具有继承关系的两个类型之间进行;

c.为避免异常,进行类型转换之前,通过instanceof运算符来判断:

if(objPri instanceof String){
   String str = (String)objPri;
}
所以,在进行强制类型转换前,先用instanceof来判断是否可以转换,避免出现ClassCastException异常;

3).instanceof运算符

a.instanceof运算符的前一个操作符通常是一个引用类型,后一个运算符通常是一个类或者接口,用于判断前面的对象是否是后面的类或者其子类,实现类的实例;

b.instanceof运算符签名操作数的编译时类型要么与后面的类相同,要么与后面的类具有继父子继承关系;

c.instanceof作用:在进行强制类型转换前,首先判断前一个对象是否是后一个类的实例;

8.继承与组合

继承最大的坏处:破坏封装;

1).使用继承的注意点

父类通常遵循如下规则:

a.尽量隐藏父类的内部数据,尽量把所有的成员变量设置为private权限;

b.如果父类中的方法需要被外部类调用,则必须以public修饰但又不希望子类重写该方法,可以使用final修饰符;如果希望父类的某个方法被子类重写但不希望被其他类自由访问,可以使用protected修饰;

c.尽量不要在父类构造器中调用将要被子类重写的方法;

当系统new一个对象时,会先执行其父类构造器,如果父类构造器调用了一个方法,而这个方法又被其子类重写了,就会变成调用被子类重写后的方法,这个时候,这个方法可能使用了子类对象未初始化的变量,就可能发生空指针异常!

2).利用组合实现复用

9.初始化块

1).使用初始化块

a.相同类型的初始化块之间有顺序:前面定义的初始化块先执行后面定义的初始化块后执行;

b.修饰符:static  >  静态初始化块;

c.初始化块只在创建对象时隐式执行,而且在构造器之前执行;

d.当Java创建一个对象时,系统先为该对象的所有实例变量分配内存,接着开始对这些实例执行初始化,初始化顺序:

先执行初始化块或声明实例变量时指定的初始值(谁在前,先执行),再执行构造器里指定的初始值;

2).初始化块和构造器

a.初始化块的用法:如果有一段初始化处理代码对所有的对象完全相同,且无须接受任何参数,就可以把这段初始化处理代码提取到初始化块中;

b.实际上,初始化时一个假象使用javac编译类后,初始化块会消失,还原到每个构造器中,且位于构造器所有代码的前;

c.与构造器类似,创建对象时,不仅会执行该类的普通的初始化块和构造器,系统会一直追溯到Object类,先执行Object类的初始化块,再执行Object类的构造器,依次向下执行其父类的初始化块,再执行其父类的构造器......最后才执行该类的初始化块好构造器,返回该类的对象;

总结:也就是从继承树的顶端开始,按照先初始化块后构造器的顺序执行,依次每一层树的执行;

3).静态初始化块

a.普通初始化块负责对对象执行初始化,类初始化块负责对类进行初始化;

b.系统在类初始化阶段执行静态初始化块而不是在创建对象时才执行,因此静态初始化块总是比普通初始化块先执行;

总结:从继承树的顶端开始,先执行每一层的静态初始化块,依次每一层执行完之后,再次从顶端开始,执行普通初始化块以及构造器函数,依次每一层执行;


相关文章

    暂无相关文章

用户点评