第五章 面向对象(上) 疯狂 Java 讲义

面向对象四个基本特征:抽象,继承,封装,多态性。

类可以被认为是一种自定义的数据类型,可以使用类来定义变量,所有使用类定义的变量都是引用变量。类用于描述客观世界中某一类对象的共同特征,而对象则是类的具体存在。

类(class)和对象(object,也叫实例,instance),类可以理解成某种概念,对象才是一个具体存在的实体。对象是类的实例。

一个类定义包含三个最常见的成员:构造器、成员变量和方法。
构造器可写可不写,不写系统会默认指定一个,写的话要注意构造器的名字与类名相同;构造器不能定义 void,不能声明返回值类型。

创建对象:
Person p;
p = new Person();
简写:
Person p = new Person();
上面这行代码产生了两个东西,一个是变量 p,一个是 Person 对象。变量 p 本身只储存了一个地址值,并未包含实际数据,但指向实际的 Person 对象。
﹝static 修饰的方法和成员变量,既可以通过类来调用,也可以通过实例调用(疯狂 Java 讲义的作者认为,类成员变量和类方法就不应该允许通过实例调用,这里是 Java 语言设计的混淆之处)。没有使用 static 修饰的,只能通过实例来调用。﹞
静态成员不能直接访问非静态成员。
如果确实需要在静态方法中访问一个普通方法,只能重新创建一个对象,
Person person = new Person();
person.***();

Java 编程时不要用实例去调用 static 修饰的成员变量和方法,而是用类去调用。

对象的 this 引用
this 关键字总是指向调用该方法的对象。

方法详解
Java 中的方法不能独立存在,必须属于某个类或者对象。在结构化语言中,函数是第一公民,在面向对象语言中,类是第一公民,方法必须属于类或对象。
所有的方法都必须通过“类.方法”或者“对象.方法”的形式调用。

Java 里面方法的参数传递只有一种:值传递。是将实际参数值的复制品传入到方法中。当系统执行方法时,系统为形参执行初始化,把实参变量的值赋给形参变量,方法里操作的不是实际的实参变量。
引用类型的参数传递实际上还是值传递,只是传递(对形参初始化)的是引用该对象的内存地址值(指针),方法中形参所指向的还是那个对象,因此改变方法中的引用参数,方法外的也会改变。(传参这个行为传递的是对象的内存地址值,然后对象的内存地址值赋给了形参,形参是实参的内存地址值的拷贝)

形参个数可变的方法:
..
public static void test(int a , String... books)
..
一个方法最多包括一个长度可变的形参。

递归方法一定要向已知的方向递归。

方法重载
Java 中一个类允许定义多个同名方法,只要形参列表不同即可。这叫做重载。

成员变量和局部变量
所有变量:
    成员变量:
            类变量(有 static 修饰,生命周期:类的准备阶段开始—>系统销毁该类) 访问:类.类变量、实例.类变量,类变量被修改后                                       所有其他的实例也将获得这个被修改的类变量。
            实例变量(没有 static 修饰,生命周期:类的实例被创建开始—>系统销毁该实例) 访问:实例.实例变量
    局部变量:
            形参:在定义方法签名时定义的变量,形参的作用域是整个方法
            方法局部变量:在方法内部定义的变量,作用域是变量定义的地方开始到方法结束
            代码块局部变量:在代码块中定义的变量,作用域是从定义的地方开始到代码块结束
如果局部变量和成员变量同名,在方法中局部变量会覆盖成员变量,如果在方法中想要引用被覆盖的成员变量,可以使用 this(对于实例变量)或者类名(对于类变量)作为调用者来限定访问成员变量,不过应该尽量避免。

隐藏和封装
封装指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
封装是将该隐藏的隐藏,该暴露的暴露。这两个方面都需要使用 Java 提供的访问控制符来实现。



写程序追求高内聚,低耦合。

类里面的绝大部分成员变量使用 private 修饰,只有一些 static 修饰的类似于全局变量的成员变量才用 public。除此之外,有些方法用来辅助实现类中的其他方法功能的也应该用 private 实现。
如果某个类要用做其他类的父类,该类的大部分方法希望被其子类重写,而不是被外界直接调用,则使用 protected 修饰。
如果希望暴露出来给他类直接调用的方法应该使用 public 修饰。

Package、import 和 import static
包名建议用企业域名的倒序,如 com.pactera,一个父包 org.crazyit.elearning 和一个子包 org.crazyit.elearning.student,后者是前者的的一个模块,但是两者在用法上没有任何关系。如果父包要用到子包的类需要子包的全名,不能省略。

同一个包下面的类互相引用不用加前缀。
如果要创建处于其他包中的类的实例,需要使用包前缀,比如:
lee.sub.Apple a = new lee.sub.Apple();
比较繁琐,因此引入了 import 关键字,import 应该出现在 package 语句之后。上面的需要使用 Apple 类的语句可以写成:
import lee.sub.Apple;

深入构造器
构造器最大的作用是创建对象时初始化。在创建一个对象时,系统为这个对象的实例变量进行默认初始化,这种默认初始化把所有的基本类型的实例变量设为0或 false,把所有的引用类型的实例变量设为 null。
如果想要改变这种默认的初始化,可以通过构造器实现。

构造器重载
如果一个类有多个构造器形成构造器重载(名字相同,形参列表不同),且其中一个构造器包含另一个的执行体,可以在构造器 B 中调用 A。用 new 关键字来调用。


类的继承
Java 中子类继承父类的语法格式如下:
修饰符 class 子类 extends 父类{}
Java 中子类只能有一个直接父类,其父类可以有其的直接父类。

从子类角度看,子类扩展了(extends)了父类,获得了父类全部的成员变量和方法(不包括构造器);从父类的角度看,父类派生(derive)出了子类。

重写父类的方法
子类扩展了父类,一般来说,子类都是在父类的基础上增加成员变量和方法。但是有时子类需要重写父类的方法,例如鸟类都包含飞翔方法,但是鸵鸟不会飞。
子类包含父类同名方法的现象称为方法重写(Override),也叫方法覆盖。
使用 super 关键字可以调用父类中被覆盖的方法。

调用父类构造器
子类不会继承父类的构造器,但是可以调用父类构造器的代码;仍是使用 super 关键字。


多态
多态存在三个前提:1.子类扩展(继承)父类;2.子类重写父类的方法;3.子类对象赋给父类引用变量。
Animal am = new Cat();
运行时 am 可以获得父类的成员变量,重写的方法中,am 获取的是父类的类方法,子类的成员方法;子类独有的成员变量和成员方法,多态是获取不到的。

继承和组合
继承是实现类复用的方法,但是带来坏处,破坏封装;可以使用组合来实现类复用。组合能提供更好的封装性。

为了父类有良好的封装性,设计父类应该遵循如下原则:
1.尽量隐藏父类内部的数据,把父类的成员变量都设置成 private 访问类型。
2.父类中仅为辅助的工具方法,使用 private 修饰;父类中需要被子类调用的,使用 public 修饰,但又不希望子类重写该方法可以用 final 修饰;如果希望父类的某个方法被子类重写,但又不希望被其他类自有方法,可以使用 protected 修饰。
3.尽量不要在父类中调用要被子类重写的方法。

什么情况下需要从父类派生子类?需要具备以下两个条件之一:
1.子类需要增加额外的属性,不仅仅是属性值的改变;比如从 Person 类中派生 Student 类,需要提供年纪,学号属性;
2.子类需要增加独有的行为方式,比如从 Person 类中派生 Teacher 类,则 Teacher 类需要有 teaching() 方法。

如果只是出于类复用的目的,可以使用组合来实现。组合是把旧类对象作为新类的成员组合进来,用以实现新类的功能,用户看到的是新类的方法,不能看到被组合对象的方法。因此,通常需要在新类里使用 private 修饰被组合的旧类对象。
组合总结下来就是,在旧类中把新类当做成员变量并用 private 修饰,然后在构造器中初始化它,然后在新类中直接复用旧类的方法来实现目的。在最后使用,实例化创建新类对象的时候要把旧类的实例传进去。

上面的狼与动物的例子其实不应该用组合,还是用继承比较好。继承表达的是 is-a 的关系,组合表达的是 has-a 关系。

初始化块和构造器
初始化块是 Java 类中可能出现的第四种成员,一个类可以有多个初始化块(但是没有意义,全部合并为一个),前面的初始化块先执行,再执行后面的。初始化块的修饰符只能是 static(可以没有),使用 static 修饰的叫静态(类)初始化块,初始化块中可包含任何可执行性语句。初始化块在构造器之前执行。

在某种程度上看,初始化块是构造器的补充。初始化块总在构造器之前执行,系统同样可以通过初始化块来进行对象的初始化操作。
不用的是,初始化块不能接受参数,如果有多个构造器,可以将其中相同的部分提取到初始化块中执行。

使用了 static 修饰的类初始化块在类初始化阶段执行,而不是创建对象时执行,因此比普通初始化块先执行,类(静态)初始化块属于类的静态成员,遵循静态成员不能访问非静态成员的规则,类初始化块不能访问实例变量和实例方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值