封装是面向对象编程的核心思想,将对象的属性和行为封装起来,其载体就是类。
例如:创建一个类,实现餐馆点菜的场景。
package jjj666;
public class jjj666 {
public static void 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方法中实现的,代码完全暴露,我可以任意删改。如果能随意修改代码,就无法正常运作。为防止其他人修改厨师行为将厨师单独封装成一个类,将厨师的工作定义成厨师类的行为。
例7.2package jjj666;
public class jjj666 {
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 {
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);
}}
厨师有些属性和行为是不给予公开的,我们用private来修饰。此时在运行餐厅的主方法就会出现异常,提示Cook2的name和cutOnion()不可以直接调用。
例7.3package jjj666;
public class jjj666 {
public static void main(String[] args) {
Cook2 cook = new Cook2();// 创建厨师类的对象
System.out.println("**请让厨师为我做一份香辣肉丝。***");
cook.cooking("香辣肉丝");// 厨师烹饪香辣肉丝
System.out.println("**你们的厨师叫什么名字?***");
System.out.println(cook.name);// 厨师回答自己的名字
System.out.println("**请让厨师给我切一点葱花。***");
cook.cutOnion();// 厨师去切葱花
}
}
class Cook2 {
String name;//厨师的名字
public Cook2() {
this.name = "Tom Cruise";//厨师的名字叫Tom Cruise
}
void cutOnion() {//厨师切葱花
System.out.println(name + "切葱花");
}
private void washVegetavles() {//厨师洗蔬菜
System.out.println(name + "洗蔬菜");
}
void cooking(String dish) {//厨师烹饪顾客点的菜
washVegetavles();
cutOnion();
System.out.println(name + "开始烹饪" + dish);
}
}
例7.4
package jjj666;
public class jjj666 {
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) {
jjj666 water = new jjj666();// 创建餐厅对象,为顾客提供服务
System.out.println("**请让厨师为我做一份香辣肉丝。***");
water.takeOrder("香辣肉丝");// 服务员给顾客下单
System.out.println("**你们的厨师叫什么名字?***");
System.out.println(water.saySorry());// 服务员给顾客善意的答复
System.out.println("**请让厨师给我切一点葱花。***");
System.out.println(water.saySorry());// /服务员给善意的答复顾客
}
}
7.2 类的继承继承在面向对象开发思想中是一个非常重要的概念,它使整个程序框架结构具有一定的d性,还可以提高软件的可维护性和可扩展性。 基本思想:基于某个父类的扩展,制定出一个新的子类。子类可以继承父类原有的属性和方法,也可以增加原有父类所不具备的属性和方法,或者直接重写父类中的某些方法
例 7.5
package jjj666;
class Computer {// 父类:电脑
String screen = "液晶显示屏";
void startup() {
System.out.println("电脑正在开机,请等待...");
}
}
public class jjj666 extends Computer {
String battery = "5000毫安电池";// 子类独有的属性
public static void main(String[] args) {
Computer pc = new Computer();// 电脑类
System.out.println("computer的屏幕是:" + pc.screen);
pc.startup();
jjj666 ipad = new jjj666();// 平板电脑类
System.out.println("pad的屏幕是:" + ipad.screen);// 子类可以直接使用父类属性
System.out.println("pad的电池是:" + ipad.battery);// 子类独有的属性
ipad.startup();// 子类可以直接使用父类方法
}
}
7.2.2 方法的重写
例7.6
package jjj666;
class Computer2 {// 父类:电脑
void showPicture() {
System.out.println("鼠标点击");
}
}
public class kkj3 extends Computer2{
void showPicture() {
System.out.println("手指点击触摸屏");
}
public static void main(String[] args) {
Computer2 pc = new Computer2();// 电脑类
System.out.print("pc打开图片:");
pc.showPicture();// 调用方法
kkj3 ipad = new kkj3();// 平板电脑类
System.out.print("ipad打开图片:");
ipad.showPicture();// 重写父类方法
Computer2 computerpad = new kkj3();// 父类声明,子类实现
System.out.print("computerpad打开图片:");
computerpad.showPicture();// 调用父类方法,实现子类重写的逻辑
}
}
2、super 关键字
super关键字的使用方法与this关键字类似
例7.7
package jjj666;
class Computer3 {// 父类:电脑
String sayHello(){
return "欢迎使用";
}
}
public class kkj3 extends Computer3{
String sayHello() {// 子类重写父类方法
return super.sayHello() + "平板电脑";// 调用父类方法,在其结果后添加字符串
}
public static void main(String[] args) {
Computer3 pc = new Computer3();// 电脑类
System.out.println(pc.sayHello());
kkj3 ipad = new kkj3();// 平板电脑类
System.out.println(ipad.sayHello());
}
}
7.2.3 所有类的父类——Object类
在开始学习使用class 关键字定义类时,就应用了继承原理,因为在Java中,所有的类型都直接或间接继承了java.lang.Object类。Object类是比较特殊的类,它是所有类的父类,是Java类层中的最高层类。当创建一个类时,总是在继承,除非某个类已经指定要从其他类继承,否则它就是从java.lang.Object 类继承而来的,可见 Java 中的每个类都源于java.lang.Object 类,如 String、Integer 等类都是继承于 Object 类;除此之外自定义的类也都继承于Object 类。由于所有类都是 Object 子类,所以在定义类时,省略了 extends Object关键字。
例 7.8
package jjj666;
public class kkj3{
public String toString() { //重写toString()方法
return "在" + getClass().getName() + "类中重写toString()方法";
}
public static void main(String[] args) {
System.out.println(new kkj3()); //打印本类对象
}
}
例7.9
package jjj666;
class V { // 自定义类V
}
public class kkj3 {
public static void main(String[] args) {
String s1 = "123"; // 实例化两个对象,内容相同
String s2 = "123";
System.out.println(s1.equals(s2)); // 使用equals()方法调用
V v1 = new V(); // 实例化两个V类对象
V v2 = new V();
System.out.println(v1.equals(v2)); // 使用equals()方法比较v1与v2对象
}
}
7.3 类的多态
多态意为一个名字可具有多种语义,在程序设计语言中,多态性是指“一种定义,多种实现”例如,运算符“+”作用于两个整型量时是求和,而作用于两个字符型量时则是将其连接在一起。利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。类的多态性可以从两方面体现:一是方法的重载,二是类的上下转型。
7.3.1 方法的重载
方法的存在就是在同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可。
例7.10
package jjj666;
public class kkj3{
// 定义一个方法
public static int add(int a) {
return a;
}
// 定义与第一个方法参数个数不同的方法
public static int add(int a, int b) {
return a + b;
}
// 定义与第一个方法相同名称、参数类型不同的方法
public static double add(double a, double b) {
return a + b;
}
// 定义一个成员方法
public static int add(int a, double b) {
return (int) (a + b);
}
// 这个方法与前一个方法参数次序不同
public static int add(double a, int b) {
return (int) (a + b);
}
// 定义不定长参数
public static int add(int... a) {
int s = 0;
// 根据参数个数循环 *** 作
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
package jjj666;
class Quadrangle { // 四边形类
public static void draw(Quadrangle q) { // 四边形类中的方法
// SomeSentence
}
}
public class kkj3 extends Quadrangle{
public static void main(String args[]) {
kkj3 p = new kkj3(); // 实例化平行四边形类对象引用
draw(p); // 调用父类方法
}
}
例7.12
package jjj666;
class Quadrangle {
public static void draw(Quadrangle q) {
// SomeSentence
}
}
public class kkj3 extends Quadrangle {
public static void main(String args[]) {
draw(new kkj3());
// 将平行四边形类对象看作是四边形对象,称为向上转型 *** 作
Quadrangle q = new kkj3();
kkj3 p = (kkj3) q; // 将父类对象赋予子类对象
// //将父类对象赋予子类对象,并强制转换为子类型
//Parallelogram p = (Parallelogram) q;
}
}
例7.13
package jjj666;
class Quadrangle {
public static void draw(Quadrangle q) {
// SomeSentence
}
}
class Square extends Quadrangle {
// SomeSentence
}
class Anything {
// SomeSentence
}
public class kkj3 extends Quadrangle {
public static void main(String args[]) {
Quadrangle q = new Quadrangle(); // 实例化父类对象
// 判断父类对象是否为Parallelogram子类的一个实例
if (q instanceof kkj3) {
kkj3 p = (kkj3) q; // 进行向下转型 *** 作
}
// 判断父类对象是否为Parallelogram子类的一个实例
if (q instanceof Square) {
Square s = (Square) q; // 进行向下转型 *** 作
}
// 由于q对象不为Anything类的对象,所以这条语句是错误的
// System.out.println(q instanceof Anything);
}
}
7.4 抽象类与接口
7.4.1 抽象类与抽象方法在解决实际问题时,一般将父类定义为抽象类,需要使用这个父类进行继承与多态处理。回想继承和多态原理,继承树中越是在上方的类越抽象,如鸽子类继承鸟类、鸟类继承动物类等。在多态机制中,并不需要将父类初始化对象,我们需要的只是子类对象,所以在Java语言中设置抽象类不可以实例化对象,因为图形类不能抽象出任何一种具体图形,但它的子类却可以。
Java 中定义抽象类时,需要使用 abstract 关键字,其语法如下: [权限修饰符] abstract class 类名{
类体 } 用abstract 关键字定义的类称为抽象类,而使用abstract 关键字定义的方法称为抽象方法,抽象方法的定义语法如下:
[权限修饰符]abstract 方法返回值类型方法名(参数列表); 使用抽象类和抽象方法时需要遵循以下原则: (1)在抽象类中可以包含抽象方法,也可以不包含抽象方法,但是包含了抽象方法的被定位为抽象类 (2)抽象类不能直接实例化,即使抽象类中没有声明抽象方法也不能实例化。 (3)抽象类被继承后,子类需要实现其中所有的抽象方法。 (4)如果继承抽象类的子类也被声明为抽象类,则可以不用实现父类中所有的抽象方法。
例7.14
package jjj666;
public interface IMather {
void watchTV();// 看电视的方法
void cooking();// 做饭的方法
}
public class TaobaoMarker extends Market {
@Override
public void shop() {
// TODO Auto-generated method stub
System.out.println(name+"网购"+goods);
}
}
public class WallMarket extends Market {
@Override
public void shop() {
// TODO Auto-generated method stub
System.out.println(name+"实体店购买"+goods);
}
}
public class kkj3 {
public static void main(String[] args) {
Market market = new WallMarket();// 使用派生类对象创建抽象类对象
market.name = "沃尔玛";
market.goods = "七匹狼西服";
market.shop();
market = new TaobaoMarker();// 使用派生类对象创建抽象类对象
market.name = "淘宝";
market.goods = "韩都衣舍花裙";
market.shop();
}
}
例7.15
package jjj666;
interface drawTest { // 定义接口
public void draw(); // 定义方法
}
// 定义平行四边形类,该类实现了drawTest接口
class ParallelogramgleUseInterface implements drawTest {
public void draw() { // 由于该类实现了接口,所以需要覆盖draw()方法
System.out.println("平行四边形.draw()");
}
}
// 定义正方形类,该类实现了drawTest接口
class SquareUseInterface implements drawTest {
public void draw() {
System.out.println("正方形.draw()");
}
}
public class kkj3 {
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 多重继承
通过接口实现多重继承的语法如下:
class 类名 implements 接口1,接口2,...,接口n
通过类实现多个接口模拟家庭成员的继承关系。
public interface IFather { //定义一个接口
void smoking(); //抽烟的方法
void goFishing(); //钓鱼的方法
定义一个IMother接口,并在其中定义两个方法wacthTV和cooking,代码如下:
public interface IMother { //定义一个接口
void wacthTV(); //看电视的方法
void cooking(); //做饭的方法
例7.16
package jjj666;
public interface IMather {
void watchTV();// 看电视的方法
void cooking();// 做饭的方法
}
public class H7_16 implements IFather, IMather {// 继承IFather接口和IMather接口
@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 Qi();// 通过子类创建IFather接口对象
System.out.println("爸爸的爱好:");
// 使用接口对象调用子类中实现的方法
father.smoking();
father.goFishing();
IMather mather = new Qi();// 通过子类创建IMather接口对象
System.out.println("\n妈妈的爱好:");
// 使用接口对象调用子类中实现的方法
mather.cooking();
mather.watchTV();
}
}
7.4.4 区分抽象类与接口
抽象类和接口都包含可以由子类继承实现的成员,但抽象类是对根源的抽象,而接口是对动抽象。抽象类的功能要远超过接口,那为什么还要使用接口呢?这主要是由于定义抽象类的个高(因为每个类只能继承一个类,在这个类中,必须继承或编写出其子类的所有共性,因此,虽然接口在功能上会弱化许多,但它只是针对一个动作的描述,而且可以在一个类中同时实现多个接这样会降低设计阶段的难度。
抽象类和接口的区别主要有以下几点。
(1)子类只能继承一个抽象类,但可以实现任意多个接口。
(2)一个类要实现一个接口必须实现接口中的所有方法,而抽象类不必。
(3)抽象类中的成员变量可以是各种类型,而接口中的成员变量只能是public static final 的(4)接口中只能定义抽象方法,而抽象类中可以定义非抽象方法。(5)抽象类中可以有静态方法和静态代码块等,接口中不可以。
(6)接口不能被实例化,没有构造方法,但抽象类可以有构造方法。抽象类与接口的不同
例7.17
package jjj666;
public interface IFather {
void smoking();// 抽烟的方法
void goFishing();// 钓鱼的方法
}
public interface IFather {
void smoking();// 抽烟的方法
void goFishing();// 钓鱼的方法
}
public final class kkj3 {
int a = 3;
void doit() {
}
public static void main(String args[]) {
kkj3 f = new kkj3();
f.a++;
System.out.println(f.a);
}
}
例7.18
package jjj666;
class Parents {
private final void doit() {
System.out.println("父类.doit()");
}
final void doit2() {
System.out.println("父类.doit2()");
}
public void doit3() {
System.out.println("父类.doit3()");
}
}
class Sub extends Parents {
public final void doit() { // 在子类中定义一个doit()方法
System.out.println("子类.doit()");
}
// final void doit2(){ //final方法不能覆盖
// System.out.println("子类.doit2()");
// }
public void doit3() {
System.out.println("子类.doit3()");
}
}
public class kkj3 {
public static void main(String[] args) {
Sub s = new Sub(); // 实例化
s.doit(); // 调用doit()方法
Parents p = s; // 执行向上转型 *** 作
// p.doit(); //不能调用private方法
p.doit2();
p.doit3();
}
}
例7.19
package jjj666;
import static java.lang.System.out;
import java.util.Random;
class Test {
int i = 0;
}
public class kkj3{
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);
private static final int i5 = rand.nextInt(20);
public String toString() {
return i4 + " " + i5 + " ";
}
public static void main(String[] args) {
kkj3 data = new kkj3();
//data.test = new Test();
// 可以对指定为final的引用中的成员变量赋值
// 但不能将定义为final的引用指向其他引用
//data.value2++;
// 不能改变定义为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");
out.println(new kkj3());
out.println(data);
}
}
例7.20
package jjj666;
import java.util.Random;
import static java.lang.System.out;
public class kkj3 {
private static Random rand = new Random(); // 实例化一个Random类对象
// 随机产生0~10之间的随机数赋予定义为final的a1
private final int a1 = rand.nextInt(10);
// 随机产生0~10之间的随机数赋予定义为static final的a2
private static final int a2 = rand.nextInt(10);
public static void main(String[] args) {
kkj3 fdata = new kkj3(); // 实例化一个对象
// 调用定义为final的a1
out.println("重新实例化对象调用a1的值:" + fdata.a1);
// 调用定义为static final的a2
out.println("重新实例化对象调用a1的值:" + fdata.a2);
// 实例化另外一个对象
kkj3 fdata2 = new kkj3();
out.println("重新实例化对象调用a1的值:" + fdata2.a1);
out.println("重新实例化对象调用a2的值:" + fdata2.a2);
}
}
例7.21
public class kkj3 {
innerClass in = new innerClass(); // 在外部类实例化内部类对象引用
public void ouf() {
in.inf(); // 在外部类方法中调用内部类方法
}
class innerClass {
innerClass() { // 内部类构造方法
}
public void inf() { // 内部类成员方法
}
int y = 0; // 定义内部类成员变量
}
public innerClass doit() { // 外部类方法,返回值为内部类引用
// y=4; //外部类不可以直接访问内部类成员变量
in.y = 4;
return new innerClass(); // 返回内部类引用
}
public static void main(String args[]) {
kkj3 out = new kkj3();
// 内部类的对象实例化 *** 作必须在外部类或外部类的非静态方法中实现
kkj3.innerClass in = out.doit();
kkj3.innerClass in2 = out.new innerClass();
}
}
例7.22
package jjj666;
interface OutInterface { // 定义一个接口
public void f();
}
public class kkj3 {
public static void main(String args[]) {
OuterClass2 out = new OuterClass2 (); // 实例化一个OuterClass2对象
// 调用doit()方法,返回一个OutInterface接口
OutInterface outinter = out.doit();
outinter.f(); // 调用f()方法
}
}
class OuterClass2 {
// 定义一个内部类实现OutInterface接口
private class InnerClass implements OutInterface {
InnerClass(String s) { // 内部类构造方法
System.out.println(s);
}
public void f() { // 实现接口中的f()方法
System.out.println("访问内部类中的f()方法");
}
}
public OutInterface doit() { // 定义一个方法,返回值类型为OutInterface接口
return new InnerClass("访问内部类构造方法");
}
}
例7.23
package jjj666;
public class kkj3 {
private int x;
private class Inner {
private int x = 9;
public void doit(int x) {
x++; //调用的是形参x
this.x++; //调用内部类的变量x
kkj3.this.x++; //调用外部类的变量x
}
}
}
例7.24
package jjj666;
public interface kkj3 {
}
class OuterClass3 {
public kkj3 doit(final String x) { // doit()方法参数为final类型
// 在doit()方法中定义一个内部类
class InnerClass2 implements kkj3 {
InnerClass2(String s) {
s = x;
System.out.println(s);
}
}
return new InnerClass2("doit");
}
}
例7.25
package jjj666;
public interface kkj3 {
}
class OuterClass4 {
public kkj3 doit() { // 定义doit()方法
return new kkj3() { // 声明匿名内部类
private int i = 0;
public int getValue() {
return i;
}
};
}
例7.267.6.4 静态内部类
可以这样认为,普通的内部类对象隐式地在外部保存了一个引用,指向创建它的外部类对象但如果内部类被定义为static,就会有更多的限制。静态内部类具有以下两个特点:
(1)如果创建静态内部类的对象,不需要创建其外部类的对象;
(2)不能从静态内部类的对象中访问非静态外部类的对象。
package jjj666;
public class kkj3 {
int x = 100;
static class Inner {
void doitInner() {
// System.out.println("外部类"+x);
}
public static void main(String args[]) {
System.out.println();
}
}
}
例7.27
package jjj666;
public class kkj3 extends ClassA.ClassB { // 继承内部类ClassB
public kkj3(ClassA a) {
a.super();
}
}
class ClassA {
class ClassB {
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)