第七章 面向对象核心技术总结

7.1 类的封装

  7.2 类的继承

7.2.1 extends 关键词

7.2.2方法的重写

7.2.3 所有类的父类---Object类

7.3 类的多态

7.3.1 方法的重载

7.3.2 向上转型

7.3.3 向下转型

7.3.4 instanceof关键词

7.4 抽象类与接口

7.4.1 抽象类与抽象方法

7.4.2 接口的声明及实现

7.4.3 多重继承

7.4.4 区分抽象类与接口

7.5 访问控制

7.5.1 访问控制符

7.5.2 Java类包

7.5.3 final关键字

7.6 内部类

7.6.1 成员内部类

7.6.2 局部内部类

7.6.3 匿名内部类

7.6.4 静态内部类

7.6.5 内部类的继承

7.7 小结

7.1 类的封装

封装:封装是面向对象编程的核心思想,将对象的属性和行为封装起来,其载体就是类.

例7.4 将厨师对象封装在餐馆类中,顾客无法接触到厨师任何信息.

 这个例子我们就能够看出,作为顾客,我始终是和服务员进行 交流,再由服务员与厨师进行交流,整个过程中,顾客与厨师是完全没有任何交流的,作为顾客,我不知道我品尝的菜是哪位厨师烹饪出来的,这种编程模式就是封装.

将对象的属性和i行为封装起来的载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想.

  7.2 类的继承

继承在面向对象开发思想中是一个非常重要的概念,它使整个程序架构具有一定的弹性,在程序中复用已经定义完善的类不仅可以减少软件开发周期,还可以提高软件的可维护性和可扩展性.

  7.2.1 extends 关键词

在Java中,让一个类继承另一个类,用extends关键字,语法如下:

child extend parents

 注意:该继承只支持单继承,及,即一个子类只能继承一个父类.

class Computer{//父类:电脑
	String screen = "液晶显示屏";
	void startup() {
		System.out.println("电脑正在开机,请等待...");
	}
	}
	

public class Pad extends Computer{
	String battery = "5000毫安电池";
	public static void main(String[] args) {
		Computer pc = new Computer();//电脑类
		System.out.println("Computer的屏幕是:" + pc.screen);
		pc.startup();
		Pad ipad = new Pad();//平板电脑类
		System.out.println("pad的屏幕是:" + ipad.screen);//子类可以直接使用父类属性
		System.out.println("pad的电池是:" + ipad.battery);//子类独有的属性
        ipad.startup();//子类可以直接使用父类方法
	}
}

7.2.2方法的重写

1.重写的实现

继承并不只是扩展父类的功能,还可以重写父类的成员方法.

重写:还可称为覆盖,就是在子类中将父类的成员方法名称保留,重新编写成员的方法的实现内容,重新编写成员方法的实现内容,更改成员方法的存储权限,或是修改成员方法的返回值类型.

重构:子类与父类的成员方法返回值,方法名称,参数类型及个数完全相同,唯一不同的方法是实现内容,(特殊的重写方法)

当重写父类方法时,修改方法的权限只能从小到大的范围改变,且必须遵循的原则,即重写的返回值类型必须时父类中同一方法返回值类型的子类

class Computer2 {// 父类:电脑
     void showPicture() {
    System.out.println("鼠标单击");
}
}
public class Pad2 extends Computer2 {//子类:平板电脑
       void showPicture() {
     System.out.println("手指点击触摸屏");
}
 public static void main (String[] args){
  Computer2 pc = new Computer2();//电脑类
System.out.print("pc打开图片:");
pc.showPicture();//调用方法
Pad2 ipad = new Pad2;//平板电脑类
System.out.print("ipad 打开图片:");
ipad.showPicture();//重写父类方法
Computer2 cmputerpad = new Pad2();//父类声明,子类实现
System.out.print("computerpad打开图片:");
coputerpad.showPicture();//调用父类方法,实现子类重写的逻辑
}
}

 2.super关键字

super关键字的使用方法与this关键字类似.this关键字代表本类对象,suoer关键字调用父类对象,使用方法如下:

super.propery;//调用父类的属性
super.method();//调用父类的方法

class Computer83{//父类:电脑
     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.2.3 所有类的父类---Object类

在Java中,所有的类都直接或间接继承了java.lang.Object类。Object类是比较特殊的类,它是所有类的父类,是JAVA类层中的最高类.

Object类中的getClass(),notify(),notifyAll(),wait()等方法不能被重写,因为这些方法被定义为final类型.

Object类中几个重要方法.

1.getClass()方法

getClass()方法是Obiect类定义的方法,它会返回对象执行的Class实例,然后使用此实例调用getName()方法可以取得类的名称.

语法如下:getClass().getName();

可以将getClass()方法与toString()方法联合使用.

2.toString()方法

toString()方法的功能是将一个对象返回字符串形式,它会返回一个String实例.当这个类转换为字符串或字符串连接,将自动调用重写的toString()方法.

public class ObjectInstance {
     public String toString()  {    //重写toString()方法
         return "在" + getClass().getName() + "类中重写toString()方法";
}
   public static void main(String[] args)  {
        System.out.println(new ObjectInstance());  //打印本类对象
}
}

3.equals()方法

前面章节曾讲解过equals()方法,当时是比较"=="运算符与equal()方法,说明"=="比较的是两个对象的引用是否相等,而equals()方法比较的是两个对象的实际内容.

class V {
  }
public class OverWriteEquals {
    public static void main(String[] agrs) {
       String s1 = "123";   //实例化两个对象,内容相等
       String s2 = "123";
    System.out.println(s1.equal(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 方法的重载

方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可.

public class OverLoadTest   {  //定义一个方法
    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(int ... a  ) {
    int s = 0;//根据参数个数循环操作
    for (int i = 0;i<a.length;i++)   {
       s +=a[i]; //将每个参数的值相加
}
     return s; //将计算结果返回
}
   public static void main(String srgs[]) {
   System.out.println("调用add(int)方法:" + add(1));
      System.out.println("调用add(int,int)方法:" + add(1,2));

   System.out.println("调用add(double,double)方法:" + 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.3.2 向上转型

常规的继承图都是将顶级类设置在页面的顶部,然后逐渐向下,所以将子类对象看作是父类对象被称为"向上转型".

class Quadrangle  {      //四边形类
      public static void draw (Quadrangle q) {   //四边形类中的方法
          //SomeStence
  }
    }
public class Parallelogram  extends Quadrangle {  //平行四边形类,继承了四边形类
    public static void miain(String args[]) {
     Parallelogram p = new parallelogram(); //实例化平行四边形类对象引用
        draw(p);     // 调用父类
 }
 }

  7.3.3 向下转型

从下面代码可看出,越是具体的对象具有的有特性越多,越抽象的对象具有的特性越少.在做向下转型

操作时,将特性范围小的对象转换为特性范围大的对象肯定会出现问题,所以这时需要告知编译器这个四边形就是平行四边形.将父类对象强制转换为某一个子类对象 这种方式称为显示类型转换.

class Quadrangle  {      //四边形类
      public static void draw (Quadrangle q) {   //四边形类中的方法
          //SomeStence
  }
    }
public class Parallelogram  extends Quadrangle {  //平行四边形类,继承了四边形类
    public static void miain(String args[]) {
draw(new Parallelogram());
//将平行四边形类对象看作是四边形对象,称为向上转型操作
     Parallelogram p = new parallelogram(); 
//将父类对象赋予子类对象,并强制转换为子类型
  Parallelogram p = (Parallelogram) q;
 }
 }

  7.3.4 instanceof关键词

当在程序中执行向下转型操作时,如果父类对象不是子类对象的实例,就会发生ClassCastException异常,所以在执行向下转型之前需要养成一个良好的习惯,就是判断父类对象是否为子类对象的实例.这个通常用instanceof操作符来完成.可以使用instanceof操作符判断是否一个类实现了某个接口,也可以用来判断一个实例对象是否属于一个类.

instanceof语法如下:

myobiect instanceof ExampleClass

 myobject:某类的对象引用

 ExampleClass:某个类

使用instanceof操作符的表达式返回值为布尔值,如果返回值为true,说明myobject对象为ExampleClass的实例对象:如果返回值为false,说明myobject对象不是ExampleClass的实例对象.

class Quadrangle  {      //四边形类
      public static void draw (Quadrangle q) {   //四边形类中的方法
          //SomeSentence
  }
    }
class Square extends Quadrangle {
//SomeSentence
public class Parallelogram  extends Quadrangle {  //平行四边形类,继承了四边形类
    public static void miain(String args[]) {
Quadrangle q = new Quadrangle();  //实例化父类对象
//判断父类对象是否为Parallelogram子类的一个实例
if (q instanceof Parallelogram) 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 方法返回值类型 方法名(参数列表);

 从上面的语法可以看出,抽象方法是直接以分号结尾的,它没有方法体,抽象方法本身没有任何意义,除非它被重写,而承载这个抽象方法的抽象类必须被继承,实际上,抽象类除了被继承之外没有任何意义.

构造方法不能定义为抽象方法

 public abstract class Market {
public String name;     //商场名称

public String goods;     //商场名称

public abstract void shop();     //抽象方法,用来输出信息

 定义一个TaobaoMarket类,继承自Market抽象类,实现其中的shop抽象方法;

public class TaobaoMarket extends Market {
@Override

public void shop()  {
//TODO Auto-generated method stub

System.out.println(name+"网购"+goods);

          }

}

定义一个WallMarket类,继承自Market抽象类,实现其中shop抽象方法:

 

public class WallMarket extends Market {
@Override

public void shop()  {
//TODO Auto-generated method stub

System.out.println(name+"实体店购买"+goods);

          }

}
public class GOShopping
{
     public stadtic void main(String[] args)
    {
    Market market = new WallMarket();//使用费派生类对象创建抽象对象
    Market.name = "沃尔玛";
    market.goods = "七匹狼西服"; 
    market.shop =();
    market = new TaobaoMarket();//使用费派生类对象创建抽象对象
    market.name = "淘宝";
    market.goods = "韩都衣舍花裙";
    market.shop();
    }
}

 

使用抽象类和抽象方法时需要遵守以下原则:

(1)在抽象类中,可以包含抽象方法,也可以不包含抽象方法,但是包含了抽象方法的类必须被定义为抽象类。

(2)抽象类不能直接实例化,即使抽象类中没有声明抽象方法,也不能实例化。

(3)抽象类被继承后,子类需要实现其中所有的抽象方法。

(4)如果继承抽象类的子类也被声明为抽象类,则可以不用实现父类中所有的抽象方法。
 

 7.4.2 接口的声明及实现

接口是抽象的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体,可以将draw()方法封装到一个接口中,这样可以让一个类既能继承图形类又能实现draw()方法接口,这就是接口存在的必要性.

使用interface关键词进行定义,其语法如下:

[修饰符] interface 接口名 [extends 父接口名列表] {
  [public] [static] [final] 常量;
  [public] [abstract] 方法;

}

 修饰符:可选,用于指定接口的访问权限,可选值为public.

接口名:必选参数,用于指定接口的名称,接口名必须是合法的Java标识符.一般情况下要求首字母大写.

extends:父接口名列表:可选参数,用于指定要定义的接口继承于哪一个父接口,父接口名必为必选参数.

方法:接口中的方法只有定义而没有被实现.

一个类实现一个接口可以使用implements关键字

public class Parallelogram extends Quadrangle implements drawTest {
...//
}

  7.4.3 多重继承

在Java中类不允许多重继承,但使用接口就可以实现多重继承,因为是一个类可以同时实现多个接口,这样可以将所有需要实现的接口放置在implements关键词后使用逗号","隔开,但可能会在一个类中产生庞大的代码量,因为继承一个接口时需要实现接口中所有的方法.

通过接口实现多重继承的语法如下:

class 类名 implements 接口1,接口2,...,接口n

如果是接口承接接口,使用extends关键字,而不是implements关键字,例如:
interface intf1 {
}
  interface intf2 extends intf1 {
}
另外,如果遇到接口继承接口,则子类在实现子接口时,需要同时实现父接口和子接口中定义的所有方法,例如:
 interface Father {    //定义父接口
     void fatherMethod();//父接口方法
}
interface Child extends Father {  //定义子接口,继承父接口
   void childMethod(); //子接口方法
}
  public class InterfaceExtends implements Child { //实现子接口,但必须重新写所有方法
    public void fatherMethod() {
    System.out.println("实现父接口方法");
}
Public void childMethod() {
  System.out.println("实现子接口方法");
}
}

  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 类名{ }

 final class FinalClass  {
    int a = 3;
void doit() {
   }
Public static void main(String args[] ) {
     FinalClass f = new FinalClass();
     f.a++;
     System.out.println(f.a);
}
}

 2.final方法

private final void test() {
   ...//省略一些程序代码
}
      
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 FinalClass {
 public static void main(String[] args) {
  Sub s = new Sub();             //实例化
  s.doit();                      //调用doit()方法
  Parents p = s;                 //执行向上转型操作
  //p.doit();                    //不能调用private方法
  p.doit2();
  p.doit3();
 }
}

 

3、final 变量

final 关键字可用于变量声明(定义的变量必须在声明时对其进行赋值操作) ,一旦该变量被设定,就不可以再改变该变量的值。

final double PI=3.14;

 

 

 

7.6 内部类

7.6.1 成员内部类
1、成员内部类简介

 在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量。

在内部类中可以随意使用外部类的成员方法以及成员变量。

成员内部类的语法如下:

public class OuterClass {      //外部类

   private class InnerClass  {   //内部类

           //...

    }

}
public class OuterClass {
  innerClass  in = new innerClass();  //在外部类实例化内部类对象引用
     public void outc()  {
          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[]) {
    OuterClass out = new OuterClass(); 
//内部类的对象实例化操作必须在外部或外部类的非静态方法中实现
  OuterClass.innerClass in = out.doit();
  OuterClass.innerClass in2 = out.new innerClass();
}
}

 

例如,在主方法中实例化一个内部类对象。

public class void main(String args[]) {
OuterClass out = new OuterClass();

OuterClass.innerClass in =out.doit();

OuterClass.innerClass in2=out.new innerClass();  //实例化内部类对象

2.内部类向上转型为接口 

 

 3、使用this关键字获取内部类与外部类的引用

 如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字。

使用成员内部类时,应该遵循以下原则:

(1)可以有各种修饰符,可以用private、public、protectd、static、final 、abstract等修饰符。

(2)如果有内部类有static限定,就是类级别的,否则为对象级别.类级别可以通过外部类直接访问,对象级别需要先生成外部类的对象后才能访问;

(3)内部类不能同名;

(4)非静态内部类中不能声明任何static成员;

(5)内部类可以互相调用;
 

public class TheSameName {
   private int x;
  private class Inner {
    private int x = 9;
    public void doit (int_x) {
            x++;                        //调用的是形参x
            this.x++;                  //调用内部类的变量x
            TheSameName.this.x++;     //调用外部类的变量x
       }
   }
}

  7.6.2 局部内部类

局部类不仅可以在类中进行定义,也可以在类的局部位置定义,如在类的方法或任意的作用域中均可以定义内部类。

interface OutInterface2 {
}
class OuterClass3 {
       public OutInterface2 doit (final String x) {  //doit()方法参数为final类型
       //在doit()方法中定义一个内部类
        class InnerClass2 implements OutInterface2 {
          InnerClass2(String s) {
              s = x;
            System.out.println(s);
         }
      }
            return new InnerClass2("doit");
      }
 }

  7.6.3 匿名内部类

匿名类所有实现代码都需要在大括号之间进行编写。语法如下:

return new A() {     //A指类名

      ...//内部类体

};

 

 使用匿名内部类时应该以下原则:

(1)匿名类没有构造方法

(2)匿名类不能定义静态的成员

(3)匿名类不能用private、public、protectd、static、final 、abstract等修饰

(4)只可以创建一个匿名类实例

  7.6.4 静态内部类

在内部类前添加修饰符static ,这个内部类就变为静态内部类了。

静态内部类具有以下两个特点:

(1)如果创建静态内部类的对象,不需要创建其外部类的对象;

(2)不能从静态内部类的对象中访问非静态外部类的对象。

public class StaticInnerClass {
   int x = 100;
  static class Inner {
        void doitInner() {
           //System.out.prinln("外部类"+x); //不能调用外部类的成员变量x
           }
      }
}
 
 
 
            在静态内部类中定义主方法
    +   public static void main(String args[]) {
               System.out.prinln();  

  7.6.5 内部类的继承

内部类和其他普通类一样可以被继承,但是继承内部类比继承普通类复杂,需要设置专门的语法来完成。

public class OutputInnerClass extends ClassA.ClassB {
       public OutputInnerClass(ClassA a) {
         a.super();
         }
   }
class ClassA {
   class ClassB {
     }
}

在某个类继承内部类时,必须硬性给予这个类带参数的构造方法,并且该构造方法的参数必须是该内部类的外部类引用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值