7.1 类的封装
封装是面向对象编程的核心思想,将对象的属性和行为封装起来,其载体就是类。
例如:创建一个类,实现餐馆点菜的场景
public class Restaurant1 {
public static viod main(String[] args) {
String cookName="Tom Cruise"; //厨师的名字叫Tom Cruise
System.out.println("**请厨师为我做一份香辣肉丝。***");
System.out.println(cookName + "加葱花");
System.out.println(cookName + "洗蔬菜");
System.out.println(cookName + "开始烹饪" + "香辣肉丝");
System.out.println( "请问厨师叫什么名字?***");
System.out.println(cookName)
System.out.println( "**请厨师给我切一点葱花。***");
System.out.println(cookName + "切葱花");
所有的逻辑代码全是在main方法中实现的,代码完全暴露,我可以任意删改。如果能随意修改代码,就无法正常运作。为防止其他人修改厨师行为将厨师单独封装成一个类,将厨师的工作定义成厨师类的行为。
厨师有些属性和行为是不给予公开的,我们用private来修饰。此时在运行餐厅的主方法就会出现异常,提示Cook2的name和cutOnion()不可以直接调用。
顾客与厨师是完全没有交集的,厨师是对顾客隐藏起来的,被封装在餐馆的类当中。这种编程模式就是封装。
public class Restaurant {
private Cook2 cook = new Cook2 (); //餐厅封装的厨师类
public static void takeOrder (String dish) { //下单
cook.cooking(dish); //通知厨师做菜
System.out.println("您的菜好了,请慢用。");
}
public String saySorry() {//拒绝客户要求
return "抱歉,餐厅不提供此项服务。";
}
public static void main(String[] args) {
Restaurant waiter = new Restaurant();//创建餐厅对象,为顾客提供服务
System.out.println("**请厨师为我做一份鱼香肉丝。***");
waiter.takeOrder("鱼香肉丝");//服务员给顾客下单
System.out.println("**你们厨师叫什么名字?***");
System.out.println(waiter.saySorry());//服务员给顾客善意的答复
System.out.println("**请厨师给我切一点葱花。***");
System.out.println(waiter.saySorry());//服务员给顾客善意的答复
}
}
封装的思想:将对象的属性和行为封装起来的载体就是类,类通常对顾客隐藏其实现细节。
7.2 类的继承
继承在面向对象开发思想中是一个非常重要的概念,它使整个程序框架结构具有一定的弹性,还可以提高软件的可维护性和可扩展性。
基本思想:基于某个父类的扩展,制定出一个新的子类。子类可以继承父类原有的属性和方法,也可以增加原有父类所不具备的属性和方法,或者直接重写父类中的某些方法
7.2.1 extends关键字
让一个类继承另一个类,用extends关键字,语法如下
child extends parents
这里child这个类作为子类继承parents这个类,并继承parents中的属性和方法。
注意:Java中的类只支持单继承,即一个子类只能继承自一个父类。
7.2.2 方法的重写
1、重写的实现
(1)继承并不只是扩展父类的功能,还可以重写父类的方法。
(2)重写(覆盖):在子类中将父类的成员方法的名称保留,重新编写成员方法的实现内容,更改成员方法的储存权限,或是修改成员方法的返回值类型。
(3)特殊的重写方式:子类与父类的成员方法返回值、方法名称、参数类型及个数完全相同,唯一不同的是方法实现内容,这种方式被称为重构。
注意:当重写父类方法时,修改方法的修饰权限只能从小范围到大的范围改变。
注意:一个类只可以有一个父类。
2、super 关键字
super关键字的使用方法与this关键字类似
super.property; //调用父类的属性
super.method(); //调用父类的方法
在继承的机制中,创建一个子类对象,将包含一个父类对象。两者的区别在于后者来自外部,而前者来自子类对象的内部。
7.2.3 所以类的父类——Object类
在Java中,所有的类都直接或间接继承了java.lang.Object类。Object类是比较特殊的类,它是所有类的父类,是Java类的最高层类。
Object类中主要包括clone()、finalize()、equals()、toString()等方法。其中equals()、toString()较为常用。
所有的类都是Object类的子类,所以任何类都可以重写Object类中的方法。
1、getClass()方法
Class().getName();get
2、toString()方法
功能:将一个对象返回为字符串形式,它会返回一个String实例。为对象提供一个特定的输出模式
3、equals()方法
equals()方法比较的是两个对象的实际内容。要想真正做到比较,需要在自定义类中重写equals()方法
7.3 类的多态
多态意为一个名字可具有多种语义。利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。
类的多态可以从两个方面体现:一是方法的重载,二是类的上下转型。
7.3.1 方法的重载
方法的重载意义:在同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可。
重载与重写是两个完全不同的概念,重载主要用于一个类内实现若干重载的方法。这些方法的名称相同而参数形势不同;而重写主要用于子类继承父类时,重新实现父类中的非私有方法。
7.3.2 向上转型
把子类对象赋值给父类类型的变量,这种技术被称为“向上转型”。
在执行向上转型操作时,父类的对象无法调用子类独有的属性或者方法。
class Quadrangle { //四边形类
public static void draw( Quadrangle q) { //四边形类中的方法
//SomeSentence
}
}
public class Parallelogram extends Quadrangle { //平行四边形类,继承了四边形类
public class void main(String args[]) { //实例化平行四边形类对象引用
Parallelogram p = new Parallelogram();//调用父类方法
draw(p);
}
}
7.3.3 向下转型
通过向上转型可以推理出向下转型是将较抽象的类转换为较具体的类。
向下转型通常会出现问题:将父类对象直接赋予子类,会发生编译器错误,因为父类对象不一定是子类的实例。
越是具体的对象具有的特性越多,越抽象的对象具有的特性越少。
class Restaurant {
public static void draw( Restaurant q) {
//SomeSentence
}
}
public class parallelogram extends Restaurant {
public static void main(String[] args[]) {
draw(new parallelogram () );
//将平行四边形类对象看作是四边形对象,称为向上转型操作
Restaurant q = new parallelogram();
parallelogram p=q; //将父类对象赋予子类对象
//修改:parallelogram q= (parallelogram) q;
}
}
7.3.4 instanceof 关键字
myobject instanceof ExampleClass
class Quadrangle {
public static void draw(Quadrangle q) {
//SomeSentence
}
}
class Square extends Quadrangle {
//SomeSentence
class Anything {
//SomeSentence
public class parallelogram extends Quadrangle {
public static void main(String[] args[]) {
Quadrangle q = new Quadrangle //实例化父类对象
//判断父类对象是否为Parallelogram子类的一个实例
if (q instanceof Parallelogram) {
Parallelogram p = (Parallelogram) q; //进行向下转型操作
//判断父类对象是否为Parallelogram子类的一个实例
if (q instanceof Square) {
Square s = (Sauare) q; //进行向下转型操作
}
//由于q对象不为Aaything类的对象,所以这条语句是错误的
//System.out.println(q instanceof Anything);
}
}
注意:instanceof是Java语言的关键字,在Java中的关键字都为小写。
7.4 抽象类与接口
7.4.1 抽象类与抽象方法
在解决实际问题时,一般将父类定义为抽象类,需要使用这个父类进行继承与多态处理。
在Java语言中设置抽象类不可以实例化对象,因为图形类不能抽象出任何一种具体图像,但它的子类却可以。
[权限修饰符] abstract class 类名 {undefined
类体
}
[权限修饰符] abstract 方法返回值类型 方法名(参数列表);
注意:构造方法不能定义为抽象方法。
public abstract class Market {undefined
public String name; //商场名称
public String goods; //商场名称
public abstract void shop(); //抽象方法,用来输出信息
public String name; //商场名称
public String goods; //商场名称
public abstract void shop(); //抽象方法,用来输出信息
定义一个TaobaoMarket类,继承自Market抽象类,实现其中的shop抽象方法,代码如下:
public class TaobaoMarket extends Market {undefined
@Override
public void shop() {undefined
//TODO Auto-generated method stub
System.out.println(name+"网购"+goods);
}
}
定义一个WallMarket类,继承自Market抽象类,实现其中的shop抽象方法,代码如下:
public class WallMarket extends Market {undefined
@Override
public void shop() {undefined
//TODO Auto-generated method stub
System.out.println(name+"实体店购买"+goods);
}
}
使用抽象类和抽象方法时需要遵守以下原则:
(1)在抽象类中,可以包含抽象方法,也可以不包含抽象方法,但是包含了抽象方法的类必须被定义为抽象类。
(2)抽象类不能直接实例化,即使抽象类中没有声明抽象方法,也不能实例化。
(3)抽象类被继承后,子类需要实现其中所有的抽象方法。
(4)如果继承抽象类的子类也被声明为抽象类,则可以不用实现父类中所有的抽象方法。
注意:构造方法不能定义为抽象方法。
7.4.2 接口的声明及实现
接口是抽象类的延申,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。
接口使用关键字interface进行定义,其语法如下:
一个接口实现一个接口可以使用implements关键字,
一个接口实现一个接口可以使用implements关键字,代码如下:
public class Parallelogram extends Quadrangle implements drawTest {undefined
...//
}
7.4.3 多重继承
通过接口实现多重继承的语法如下:
class 类名 implements 接口1,接口2,...,接口n
通过类实现多个接口模拟家庭成员的继承关系。
public interface IFather { //定义一个接口
void smoking(); //抽烟的方法
void goFishing(); //钓鱼的方法
}
定义一个IMother接口,并在其中定义两个方法wacthTV和cooking,代码如下:
public interface IMother { //定义一个接口
void wacthTV(); //看电视的方法
void cooking(); //做饭的方法
创建名称为Me类,继承IFather和IMother两个接口
public class Me implements IFather, IMother { //继承IFather接口和IMother接口
public void wacthTV() { //重写wacthTV()方法
System.out.println("我喜欢看电视");
}
public void cooking() { //重写cooking()方法
System.out.println("我喜欢做饭");
}
public void smoking() { //重写smoking()方法
System.out.println("我喜欢抽烟");
}
public void goFishing() { //重写goFishing()方法
System.out.println("我喜欢钓鱼");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
IFather fater = new Me(); //通过子类创建IFather接口对象
System.out.println("爸爸的爱好:");
father.smoking(); //使用接口对象调用子类中实现的方法
father.goFishing();
Mother mater = new Me(); //通过子类创建IMother接口对象
System.out.println("\n妈妈的爱好:");
mather.cooking(); //使用接口对象调用子类中实现的方法
mather.wacthTV();
}
}
7.4.4 区分抽象类与接口
抽象类和接口的区别主要有以下几点:
(1)子类·只能继承一个抽象类,但可以实现任意多个接口。
(2)一个类要实现去一个接口必须实现接口中的所有方法,而抽象类不必。
(3)抽象类中的成员变量是可以各种类型,而接口中的成员变量只能是public static final的。
(4)接口中只能定义抽象方法,而抽象类中可以定义非抽象方法。
(5)抽象类中可以有静态方法和静态代码块等,接口中不可以。
(6)接口不能被实例化,没有构造方法,但抽象类可以有构造方法。
7.5 访问控制
7.5.1 访问控制符
所有访问控制符时,需要遵循以下原则。
(1)大部分顶级类都使用public修饰。
(2)如果某个类主要用作其他类的父类,该类中包含的大部分方法只是希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰。
(3)类中的绝大部分属性都应该使用private修饰,除非一些static或者类似全局变量的属性,才会考虑使用public修饰;
(4)当定义的方法只是用于辅助实现该类的其他方法,应该使用private修饰;
(5)希望允许其他类自由调用的方法应该使用public修饰。
7.5.2 Java类包
在Java中采用类包机制非常重要,类包不仅可以解决类名冲突问题,还可以在开发庞大的应用程序时,帮助开发人员管理庞大的应用程序组件,方便软件复用。
在类中定义包名的语法如下:
package 包名1 [.包名2[.包名3...] ];
注意:Java包的命名规则是全部使用小写字母,另外,由于包名将转换为文件的名称,所以包名不包括特殊字符
使用包中的类,其语法如下:
import 包名1 [.包名2[.包名3...] ].类名;
import com.lzw.*; //指定 com.lzw包中的所有类在程序中都可以使用
import com.lzw.Math ///指定 com.lzw包中的Math类在程序中可以使用
7.5.3 final 关键字
1.final类
定义为final的类不能被继承
final的语法如下:
final class 类名{ }