7.1类的封装
目录
封装是面向对象编程的核心思想,将对象的属性和行为封装起来,其载体就是类。
例7.1
代码
package 第七章;
public class WWW1 { //创建类
public static void main(String[] args) {//主函数
// TODO Auto-generated method stub
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 +"切葱花"); //输出切葱花
}
}
结果
例7.2
代码
package 第七章;
public class QQQ2{ //创建类
public static void main(String[] args) { //主函数
Cook1 cook = new Cook1(); // 创建厨师类的对象
System.out.println("**请让厨师为我做一份香辣肉丝。***"); //输出
cook.cooking("香辣肉丝"); // 厨师烹饪香辣肉丝
System.out.println("**你们的厨师叫什么名字?***");//输出**你们的厨师叫什么名字?***
System.out.println(cook.name); // 厨师回答自己的名字
System.out.println("**请让厨师给我切一点葱花。***");//输出**请让厨师给我切一点葱花。***
cook.cutOnion(); // 厨师去切葱花
}
}
class Cook1 { //创建Cook1类
String name;// 厨师的名字
public Cook1() { //普通类
this.name = "Tom Cruise"; // 厨师的名字叫Tom Cruise
}
void cutOnion() { // 厨师切葱花
System.out.println(name + "切葱花"); //输出厨师切葱花
}
void washVegetavles() { // 厨师洗蔬菜
System.out.println(name + "洗蔬菜"); //输出厨师洗蔬菜
}
void cooking(String dish) {// 厨师烹饪顾客点的菜
washVegetavles(); //洗蔬菜
cutOnion(); //切洋葱
System.out.println(name + "开始烹饪" + dish); //输出name + "开始烹饪" + dish
}}
结果
将厨师封装成Cook类
将厨师单独封装成一个类,将厨师的工作定义成厨师类的行为,当我们想让厨师做菜,只能通过调用对象成员方法的方式实现,而我们却不知道这个方法到底是怎么写的,所以就无法随意修改了。餐馆没有义务告诉我们厨师的任何信息,并且厨师也不会随意受我们差遣,所以说厨师有些属性和行为是不予公开的。
例7.3
代码
public class QQQ3 { //创建类
public static void main(String[] args) { //主函数
Cook1 cook = new Cook1(); // 创建厨师类的对象
System.out.println("**请让厨师为我做一份香辣肉丝。***"); //输出结果
cook.cooking("香辣肉丝"); // 厨师烹饪香辣肉丝
System.out.println("**你们的厨师叫什么名字?***"); //输出你们的厨师叫什么名字?
System.out.println(cook.name); // 厨师回答自己的名字
System.out.println("**请让厨师给我切一点葱花。***"); //输出**请让厨师给我切一点葱花。
cook.cutOnion();// 厨师去切葱花
}
}
class Cook2 { //创建类
String name; // 厨师的名字
public Cook2() { //创建Cook2()
this.name = "Tom Cruise"; // 厨师的名字叫Tom Cruise
}
private void cutOnion() { // 厨师切葱花
System.out.println(name + "切葱花"); //输出Tom Cruise切葱花
}
private void washVegetavles() { // 厨师洗蔬菜
System.out.println(name + "洗蔬菜"); //Tom Cruise洗蔬菜
}
void cooking(String dish) { // 厨师烹饪顾客点的菜
washVegetavles(); //洗蔬菜
cutOnion(); //切洋葱
System.out.println(name + "开始烹饪" + dish); // 输出厨师烹饪顾客点的菜
}
}
例7.4
代码
public class QQQ4 { //创建类
private Cook2 cook = new Cook2(); //创建厨师类的对象
public void takeOrder(String dish) { //下单
cook.cooking(dish); //通知厨师做菜
System.out.println("你的菜好了,请慢用。"); //输出你的菜好了,请慢用
}
public String saySorry() { //拒绝顾客请求
return"抱歉,餐厅不提供此项服务。"; //输出抱歉,餐厅不提供此项服务
}
public static void main(String[] args) { //主函数
QQQ4 water = new QQQ4(); //创建新数组
System.out.println("**请让厨师为我做一份香辣肉丝。***"); //输出请让厨师为我做一份香辣肉丝
water.takeOrder("香辣肉丝"); //服务员给顾客下单
System.out.println("**请问厨师叫什么名字?***"); //输出请问厨师叫什么名字
System.out.println(water.saySorry()); //服务员给顾客善意的答复
System.out.println("**请让厨师给我切一点葱花。***"); //输出请让厨师给我切一点葱花
System.out.println(water.saySorry()); //服务员给顾客善意的答复
}
}
结果
7.2类的继承
子类继承父类(extends关键词)
object类是所有类的父类
7.2.1entends关键字
在Java中,让一个类继承另一个类,用extends 关键字,语法如下:
child extends parents
这里 child 这个类作为子类继承了 parents 这个类,并继承 parents 中的属性和方法。
举一个简单的例子:每个人都用过计算机,最常见的计算机就是台式机。后来随着科技的发展,计算机变得越来越小,台式机改良成了可移动的笔记本电脑,笔记本电脑又改良成了更轻薄的平板电脑。我们可以把普通计算机看成一个类,那么笔记本电脑和平板电脑都是这个类衍生出的子类。
例7.5代码
class QQQ52 { //父类:电脑
String screen="液晶显示屏"; //定义初值
void startup() { //返回参数
System.out.println("电脑正在开机,请等待...");//输出电脑正在开机,请等待...
}}
public class QQQ5 extends QQQ52 { //父类:电脑
String battery="5000毫安电池"; // 子类独有的属性
public static void main(String[] args) { //主函数
QQQ5 pc = new QQQ5(); // 电脑类
System.out.println("computer的屏幕是:"+pc.screen); //输出computer的屏幕是
pc.startup(); //返回参数
QQQ5 ipad = new QQQ5(); //平板电脑类
System.out.println("pad的屏幕是:"+ ipad.screen);//子类可以直接使用父类
System.out.println("pad的电池是:"+ipad.battery);//子类独有的属性
ipad.startup(); // 子类可以直接使用父类方法
}
}
结果
7.3 类的多态
7.2.2方法重写
重写:(前提是继承)
返回参数相同
方法名相同
传入参数相同
重载:
方法名相同
返回参数不相同 或者 传入参数不相同
例7.6 代码
class QQQ62 { //父类:电脑
void showPicture() { //显示图片
System.out.println("鼠标单击"); //输出鼠标单击
}
}
public class QQQ6 extends QQQ62 { //子类:平板电脑
void showPicture() { //显示图片
System.out.println("手指点击触摸屏"); //输出手指点击触摸屏
}
public static void main(String[] args) { //主函数
QQQ62 pc = new QQQ62(); //电脑类
System.out.println("PC打开图片:"); //输出PC打开图片
pc.showPicture(); //调用方法
QQQ6 ipad2 = new QQQ6(); //平板电脑类
System.out.println("ipad打开图片:"); //输出ipad打开图片
ipad2.showPicture(); //重写父类方法
QQQ62 computerpad = new QQQ6(); //父类声明,子类实现
System.out.println("computerpad打开图片:"); //输出computerpad打开图片
computerpad.showPicture(); //调用父类方法,实现子类重写的逻辑
}
}
结果
、
例7.7
代码
class Computer3{//父类:电脑
String sayHello(){//定义一个方法
return"欢迎使用";//返回一个字符串
}
}
public class Pad3 extends Computer3 {//子类:平板电脑
String sayHello(){//重写方法
return super.sayHello()+"平板电脑";//调用父类方法,在其结果后添加字符串
}
public static void main(String[] args) {//主方法
Computer3 pc=new Computer3();//电脑类
System.out.println(pc.sayHello());//调用父类的方法并输出
Pad3 ipad=new Pad3();//平板电脑类
System.out.println(ipad.sayHello());//调用子类的方法并输出
}
}
结果
例7.8
代码
结果
例7.9
代码
结果
例7.10
代码
public class QQQ10 { //创建类
public static int add(int a) { // 定义一个方法
return a; //输出a值
}
public static int add(int a, int b) {// 定义与第一个方法参数个数不同的方法
return a + b; //输出a + b值
}
public static double add(double a, double b) {// 定义与第一个方法相同名称、参数类型不同的方法
return a + b; //输出a + b值
}
public static int add(int a, double b) {// 定义一个成员方法
return (int) (a + b); //输出a + b值
}
public static int add(double a, int b) {// 这个方法与前一个方法参数次序不同
return (int) (a + b); //输出a + b值
}
// 定义不定长参数
public static int add(int... a) {// 定义不定长参数
int s = 0; //定义s初值
for (int i = 0; i < a.length; i++) {// 根据参数个数循环操作
s += a[i]; // 将每个参数的值相加
}
return s;// 将计算结果返回
}
public static void main(String args[]) { //主函数
System.out.println("调用add(int)方法:" + add(1));//输出结果
System.out.println("调用add(int,int)方法:" + add(1, 2));//输出结果
System.out.println("调用add(double,double)方法:" + add(2.1, 3.3));//输出结果
System.out.println("调用add(int a, double b)方法:" + add(1, 3.3));//输出结果
System.out.println("调用add(double a, int b) 方法:" + add(2.1, 3));//输出结果
System.out.println("调用add(int... a)不定长参数方法:"+ add(1, 2, 3, 4, 5, 6, 7, 8, 9)); //输出结果
System.out.println("调用add(int... a)不定长参数方法:" + add(2, 3, 4));//输出结果
}
}
结果
转型(前提是继承):
向上转型(自动):子类对象赋值给父类类型变量
向下转型 (强制):父类对象赋值给子类类型变量
例7.11
代码
class Quadrangle { // 四边形类
public static void draw(Quadrangle q) { // 四边形类中的方法
// SomeSentence
}
}
public class QQQ11 extends Quadrangle{ //子类继承父类
public static void main(String args[]) { //主函数
QQQ11 p = new QQQ11 (); // 实例化平行四边形类对象引用
draw(p); // 调用父类方法
}
}
例7.12
代码
public class QQQ12 extends Quadrangle { //子类继承父类
public static void main(String args[]) { //主函数
draw(new QQQ12()); //创建新数组
Quadrangle q = new QQQ12(); // 将平行四边形类对象看作是四边形对象,称为向上转型操作
QQQ12 p = (QQQ12) q; // 将父类对象赋予子类对象
//Parallelogram p = (Parallelogram) q;//将父类对象赋予子类对象,并强制转换为子类型
}
}
Object类——所有类的父类
在java中,所有的类都直接或间接继承了java.lang.Object类。Object类是所有类的父类,是java类层中的最高层类。
注意:Object类中的getClass()、notify()、notifyAll()、wait()等方法不能被重写,因为这些方法被定义为final类型。
1.getClass()方法
getClass()方法是Object类定义的方法,它会返回对象执行时的Class实例,然后使用此实例调用getName ()方法可以取得类的名称。
getClass().getName();//调用getClass()里的getName()方法
可以将getClass()方法与toString()方法联合使用。2.toString()方法
toString()方法的功能是将一个对象返回为字符串形式,它会返回一个String实例。在实际的应用中通常重写toString()方法。
例7.13
代码
class Square extends Quadrangle { //主函数
// SomeSentence
}
class Anything { //普通类
// SomeSentence
}
public class QQQ13 extends Quadrangle { //子类继承父类
public static void main(String args[]) { //主函数
Quadrangle q = new Quadrangle(); // 实例化父类对象
if (q instanceof QQQ13) {// 判断父类对象是否为Parallelogram子类的一个实例
QQQ13 p = (QQQ13) q; // 进行向下转型操作
}
if (q instanceof Square) { // 判断父类对象是否为Parallelogram子类的一个实例
Square s = (Square) q; // 进行向下转型操作
}
System.out.println(q instanceof Anything); // 由于q对象不为Anything类的对象,所以这条语句是错误的
}
}
7.4 抽象方法
abstract 抽象
抽象类 有抽象方法的类
抽象方法 没有方法体的 (大括号中含方法体){}
接口 interface (接口中所有的方法都是抽象方法)
implements 实现 接口 多实现
extends 继承 普通类 、抽象类 单继承
例7.14
代码
public class GoShopping { //创建类
public static void main(String[] args) { //主函数
// TODO Auto-generated method stub
Abstract market = new WallMarket();// 使用派生类对象创建抽象类对象
market.name = "沃尔玛"; //沃尔玛
market.goods = "七匹狼西服"; //七匹狼西服
market.shop(); //创建商店
market = new WallMarket();// 使用派生类对象创建抽象类对象
market.name = "淘宝"; // 淘宝
market.goods = "韩都衣舍花裙"; //韩都衣舍花裙
market.shop(); //创建商店
}
结果
7.4.2接口的声明和实现
例7.15
代码
interface drawTest { // 定义接口
public void draw(); // 定义方法
}
class ParallelogramgleUseInterface implements drawTest { // 定义平行四边形类,该类实现了drawTest接口
public void draw() { // 由于该类实现了接口,所以需要覆盖draw()方法
System.out.println("平行四边形.draw()"); //输出平行四边形
}}
class SquareUseInterface implements drawTest {//定义正方形类,该类实现了drawTest接口
public void draw() { // 由于该类实现了接口,所以需要覆盖draw()方法
System.out.println("正方形.draw()"); // 输出正方形
}}
public class QQQ15 { //创建类
public static void main(String[] args) { //主函数
drawTest[] d = { // 接口也可以进行向上转型操作
new SquareUseInterface(), new ParallelogramgleUseInterface() }; //新建数组
for (int i = 0; i < d.length; i++) { //控制长度,累加
d[i].draw(); // 调用draw()方法
}
}
}
结果
7.4.3多重继承
例7.16
代码
public class QQQ16 implements IFather,IMother{ //创建父亲母亲接口
@Override
public void watchTV() {// 重写watchTV()方法
System.out.println("我喜欢看电视");//输出我喜欢看电视
}
@Override
public void cooking() {// 重写cook()方法
System.out.println("我喜欢做饭"); //输出我喜欢做饭
}
@Override
public void smoking() {// 重写smoke()方法
System.out.println("我喜欢抽烟");//输出我喜欢抽烟
}
@Override
public void goFishing() {// 重写goFishing()方法
System.out.println("我喜欢钓鱼");//输出我喜欢钓鱼
}
public static void main(String[] args) { //主函数
IFather father = new QQQ16();// 通过子类创建IFather接口对象
System.out.println("爸爸的爱好:");//输出爸爸的爱好
father.smoking();//抽烟
father.goFishing();// 使用接口对象调用子类中实现的方法
IMother mother =new QQQ16();// 通过子类创建IMather接口对象
System.out.println("\n妈妈的爱好:");//输出妈妈的爱好
mother.cooking(); //做饭
mother.watchTV();// 使用接口对象调用子类中实现的方法
}
}
结果
7.4.4 区别抽象类与接口的区别
抽象类与接口的区别
- 子类只能继承一个抽象类,但可以实现任意多个接口
- 一个类要实现一个接口必须实现接口中的所有方法,而抽象类不必
- 抽象类中的成员变量可以是各种类型,而接口中的成员变量只能是public,static,final(修饰的变量为常量)
- 接口中只能定义抽象方法,而抽象类中可以定义非抽象犯法
- 抽象类中可以有静态方法和静态代码块等,接口中不可以
- 接口不能被实例化,没有构造方法,但抽象类可以有构造方法
7.5 访问控制
7.5.1访问控制符
使用访问控制符时,需要遵守以下原则
- 大部分顶级类都使用public修饰;
- 如果某个类主要用作其他类的父类,该类中包含的大部分方法只是希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰;
- 类中的绝大部分属性都应该使用private 修饰,除非一些static 或者类似全局变量的属性。才考虑使用public 修饰;
- 当定义的方法只是用于辅助实现该类的其他方法(即工具方法),应该使用private 修饰
- 希望允许其他类自由调用的方法应该使用public修饰。
instanceof关键字
当在程序中执行向下转型操作时,如果父类对象不是子类对象的实例,就会发生classcastException异常,所以在执行向下转型之前需要养成一个良好的习惯,就是判断父类对象是否为子类对象的实例。
myobject instanceof ExampleClass//判断是否为该类的实例对象
myobject:某类的对象引用。ExampleClass:某个类
使用instanceof操作符的表达式返回值为布尔值。
7.5.2 java 类包
7.5.3 final关键字
final 修饰的变量为常量
final 变量→不可改变的量(常量)
stastic final 静态常量
public stastic final 公有静态常量 全局常量
final 方法→不可重写
final 类→不可被继承
例7.17
代码
final class QQQ17 { //final类
int a=3; //定义初值
void doit() { //调用 doit()方法
}
public static void main(String args[]) {//主函数
QQQ17 f = new QQQ17(); //新建数组
f.a++; //累加
System.out.println(f.a); //输出结果
}
}
结果
例7.18
代码
class Parents{ //创建父类
private final void doit() { //调用final类
System.out.println("父类.doit()"); //输出调用父类
}
final void doit2() { //调用doit2()方法
System.out.println("父类.doit2()");//输出调用父类
}
public void doit3() { //调用doit3()方法
System.out.println("父类.doit3()");//输出调用父类
}
}
class Sub extends Parents { //子类继承父类
public final void doit() { //在子类中定义一个doit()方法
System.out.println("子类.doit()");//输出调用子类
}
// final void doit2(){ //调用doit2()方法
// System.out.println("子类.doit2()"); //输出调用子类
// }
public void doit3() { //调用doit3()方法
System.out.println("子类.doit3()");//输出调用子类
}
}
public class QQQ18 { //创建类
public static void main(String[] args) { //主函数
Sub s=new Sub(); //实例化
s.doit(); //调用 doit()方法
Parents p=s; //执行向上转型操作
//p.doit(); //不能调用private方法
p.doit2(); //调用 doit2()方法
p.doit3(); //调用 doit3()方法
}
}
结果
例7.19
代码
import static java.lang.System.out; // 导入System.out
import java.util.Random; // 导入需要java.util.Random的包
class Test { //类名
int i = 0;
}
public class QQQ19{ //创建类
static Random rand =new Random(); //创建新数组
private final int VALUE_1 = 9; //声明一个final常量
private static final int VALUE_2 = 10; //声明一个 final、static常量
private final Test test = new Test(); //声明一个 final引用
private Test test2 = new Test(); //声明一个不是 final 的引用
private final int[] a = {1,2,3,4,5,6 }; //声明一个定义为final 的数组
private final int i4 = rand.nextInt(20); //声明一个final常量
private static final int i5= rand.nextInt(20); //声明一个final常量
public String toString() { //调用toString()
return i4 +" "+i5+" "; //输出结果
}
public static void main(String[] args){ //主函数
QQQ19 data = new QQQ19(); //创建新数组
//data.test=new Test();
//可以对指定为final的引用中的成员变量赋值
//但不能将定义为final的引用指向其他引用
//data.VALUE_2++;
//不能改变定义为final的常量值
data.test2=new Test(); //可以将没有定义为 final的引用指向其他
for (int i = 0; i < data.a.length; i++) { //控制长度
//a[i]=9;
//不能对定义为final的数组赋值
}
out.println(data); //输出结果
out.println("data2"); //输出data2结果
out.println(new QQQ19()); //输出数组结果
out.println(data); //输出结果
}
}
结果
例7.20
代码
import java.util.Random; //接口
import static java.lang.System.out; // 导入System.out
public class QQQ20 { //创建数组
private static Random rand = new Random();//实例化一个Random类对象
private final int al =rand.nextInt(10);//随机产生0~10之间的随机数赋予定义为final的a1
private static final int a2=rand.nextInt(10); //随机产生0~10之间的随机数赋予定义为static final的a2
public static void main(String[] args) { //主函数
QQQ20 fdata= new QQQ20(); //实例化一个对象
out.println("重新实例化对象调用a1的值:"+fdata.al); //调用定义为final的al
out.println("重新实例化对象调用al的值:"+fdata.a2); //调用定义为static final的a2
QQQ20 fdata2 =new QQQ20(); //实例化另外一个对象
out.println("重新实例化对象调用al的值:"+ fdata2.al); out.println("重新实例化对象调用a2的值:"+ fdata2.a2); //输出结果
}
}
结果
7.6 内部类
例7.21
代码
public class QQQ21 { //创建类
innerClass in = new innerClass();//在外部类实例化内部类对象引用
public void ouf() { // 普通类
in.inf();//在外部类方法中调用内部类方法
}
class innerClass{ //创建innerClass
innerClass(){ //内部类构造方法
}
public void inf() { //内部类成员方法
}
int y = 0; //定义内部类成员变量
}
public innerClass doit(){ //创建innerClassdoit()方法
//y=4;
in.y = 4; //定义y值
return new innerClass(); //新建innerClass
}
public static void main(String[] args) { //主函数
QQQ21 out = new QQQ21(); //创建新数组
QQQ21.innerClass in = out.doit(); //创建新数组doit();
QQQ21.innerClass in2 = out.new innerClass();//创建新数组innerClass()
}
}
无运行结果
例7.22
代码
interface OutInterface { //接口
public void f(); // 普通类
}
public class QQQ22 { //创建类
public static void main(String[] args) { // 主函数
OutClass2 out = new OutClass2(); //实例化一个OutClass2对象
OutInterface outinter = out.doit();//调用doit()方法,返回一个OutInterface 接口
outinter.f(); //存放值
}
}
class OutClass2 { //普通类 OutClass2
private class InnerClass implements OutInterface {//定义一个内部类实现OutInterface接口
InnerClass(String s) { //返回参数
System.out.println(s); // 输出结果
}
public void f() { //创建类
System.out.println("访问内部类中的f()方法");//输出访问内部类中的f()方法
}
}
public OutInterface doit() { //创建 OutInterface doit()方法
return new InnerClass ("访问内部类构造方法"); //输出访问内部类构造方法
}
}
结果
例7.23
代码
无运行结果
7.6.2局部内部类
public class QQQ24 { //创建类
class OuterClass3 { //普通类
public QQQ24 doit(final String x) { // doit()方法参数为final类型
class InnerClass2 implements QQQ24 {// 在doit()方法中定义一个内部类
InnerClass2(String s) {// 在doit()方法中定义一个内部类
s = x; //赋值
System.out.println(s); // 输出结果
}
}
return new InnerClass2("doit"); // 输出结果doit()方法中定义一个内部类
}
}
}
无运行结果
内部类
成员内部类 和成员变量、成员方法在同一级
局部内部类 在成员方法下一级,仅在该方法内有效
静态内部类 有static修饰的内部类(成员、局部均可)
匿名内部类 没有名字的内部类(成员、局部均可)
7.6.3 匿名内部类
使用匿名内部类时应该遵循以下原则:
(1)匿名类没有构造方法;
(2)匿名类不能定义静态的成员;
(3)匿名类不能用private、public、protected、static、final、abstract等修饰;
(4)只可以创建一个匿名类实例。静态内部类:用static 修饰的类
静态内部类具有以下两个特点:
(1)如果创建静态内部类的对象,不需要创建其外部类的对象;
(2)不能从静态内部类的对象中访问非静态外部类的对象。
例7.25
代码
public interface QQQ25 { //接口
}
class OuterClass4 { //类名
public QQQ25 doit() { // 定义doit()方法
return new QQQ25() { // 声明匿名内部类
private int i = 0;
public int getValue() { //int匿名内部类
return i; //输出结果
}
};
}
}
无运行结果
例7.26
代码
public class QQQ26 { //创建类
int x = 100; //赋初值
static class Inner { //普通类名
void doitInner() { //doitInner() 调用方法
// System.out.println("外部类"+x);
}
public static void main(String args[]) { //主函数
System.out.println(); //输出结果
}
}
}
无运行结果
例7.27
public class QQQ27 extends ClassA.ClassB { // 继承内部类ClassB
public QQQ27(ClassA a) {//继承类中内部类
a.super();//构造方法体中使用 a.super()
}
}
class ClassA { //类名A
class ClassB { //内部类名B
}
}
无运行结果