1、北京 MLDN 软件实训中心 联系电话:010-51283346第(1)页 共(31)页 E-Mail:1、课程名称:面向对象(高级)2、知识点2.1、上次课程的主要知识点1、 继承的实现: 概念:继承可以扩充已有类的功能 实现:class 子类 extends 父类 ,父类又称为超类,子类又称为派生类 限制:子类可以直接继承父类中的全部非私有操作,而只能隐式继承所有的私有操作,一个子类只能继承一个父类,但是允许多层继承。 子类对象的实例化过程:在进行子类对象实例化时,首先会先对父类对象进行实例化,调用父类中的构造方法,默认情况下调用的是父类中的无参构造方法,当然也可以通过 super 指定要
2、调用的是那一个构造方法。2、 重载与覆写的区别: 重载:发生在一个类之中,方法名称相同,参数的类型或个数不同;北京 MLDN 软件实训中心 联系电话:010-51283346第(2)页 共(31)页 E-Mail: 覆写:发生在继承关系中,子类定义了一个与父类完全一样的方法,但是要注意方法的访问权限,即:被覆写的方法不能拥有比父类更严格的访问控制权限。3、 this 与 super 关键字 this 表示的是调用本类中的属性或方法,首先会从本类开始查找,如果找不到了,则再去父类中查找;而 super表示直接调用父类中的属性或方法; this 与 super 调用构造方法的时候都要放在构造方法的
3、首行,所以两者不能同时出现; this 可以表示当前对象,但是 super 无此概念。4、 final 关键字:定义的类不能有子类,定义的方法不能被子类所覆写,定义的变量就称为常量,使用 public static final声明的是全局常量。5、 抽象类:包含一个抽象方法的类称为抽象类,抽象类必须使用 abstract 关键字声明,所有的抽象类不能直接实例化,而是需要通过子类继承,之后子类(如果不是抽象类)则要覆写全部的抽象方法。6、 接口:抽象方法和全局常量的集合,称为接口,接口使用 interface 关键字进行声明,接口通过 implements 关键字被子类所实现,一个子类可以同时实
4、现多个接口,接口也可以同时继承多个接口。7、 对象多态性: 向上转型,子类对象变为父类实例,自动转型: 父类名称 父类对象 = 子类实例 ; 向下转型,将父类实例变为子类实例,强制转型: 子类名称 子类对象 = (子类名称)父类实例 ; 在进行向下转型之前一定要首先发生向上转型的关系 可以使用 instanceof 关键字判断某一个对象是否是某一个类的实例8、 Object 类:是所有类的父类 所有的类默认继承自 Object 类 主要的方法:|- toString():对象输出时调用,用于输出对象的内容|- equals():对象比较的操作 使用 Object 类可以接收任意的引用数据类型的
5、对象9、 单例设计模式(Singleton) 、多例设计。2.2、本次预计讲解的知识点1、 接口和抽象类的使用2、 包装类的操作3、 匿名内部类4、 理解 JDK 1.5 之后增加的一些新特性3、具体内容之前的很多概念基本上已经描述了一些类的定义的结构,和一些注意特点,但是所有的概念实际上都是围绕接口进行的。3.1、接口和抽象类(核心重点)接口和抽象类的使用为整个 Java 面向对象的核心,包括以后讲解的 Java 应用部分,实际上都是完全围绕着接口和抽象类的概念展开的,所以如果接口和抽象类不能理解的话,则整个的面向对象基本上就不会。北京 MLDN 软件实训中心 联系电话:010-512833
6、46第(3)页 共(31)页 E-Mail:3.1.1、为抽象类实例化抽象类中一定是要有子类的,而且子类一定要实现所有的抽象方法。通过对象多态性的学习,可以发现,当一个父类通过子类实例化之后,调用的方法肯定是被子类所覆写过的方法。abstract class Demo public void fun()System.out.println(this.getInfo() ;public abstract String getInfo() ;class DemoImpl extends Demo public String getInfo()return “Hello World!“ ;publi
7、c class CaseDemo01 public static void main(String args)Demo demo = new DemoImpl() ; / 向上转型demo.fun() ;抽象类本身可以实例化,而且通过子类实例化之后就具备了子类的具体功能,同一种功能,会根据子类的不同而有所不同,完全由子类决定。3.1.2、抽象类的使用 模板设计(理解)例如:现在可以将一个人的划分成学生和工人。 不管是工人还是学生肯定都有其共同的属性,例如:姓名、年龄。 但是,既然是一个类,肯定就拥有自己的信息,例如:学生有学校,工人有工作。abstract class Person priva
8、te String name ;private int age ;public Person(String name,int age)this.name = name ;this.age = age ;public void say()System.out.println(this.getContent() ;public abstract String getContent() ;public String getName()return this.name ;北京 MLDN 软件实训中心 联系电话:010-51283346第(4)页 共(31)页 E-Mail:public int get
9、Age()return this.age ;class Student extends Person private String school ;public Student(String name,int age,String school)super(name,age) ;this.school = school ;public String getContent()return this.toString() ;public String toString()return “姓名:“ + super.getName() + “,年龄:“ + super.getAge() + “学校:“
10、 + this.school ;class Worker extends Person private String job ;public Worker(String name,int age,String job)super(name,age) ;this.job = job ;public String getContent()return this.toString() ;public String toString()return “姓名:“ + super.getName() + “,年龄:“ + super.getAge() + “工作:“ + this.job ;public
11、class CaseDemo02 public static void main(String args)/ Person per = new Student(“张三“,20,“ 清华大学“) ;Person per = new Worker(“张三“,20,“经理“) ;per.say() ;这样的设计称为模板设计。在实际的开发中,所有的类永远不要去继承一个已经实现好的类,而只能继承抽象类或实现接口。北京 MLDN 软件实训中心 联系电话:010-51283346第(5)页 共(31)页 E-Mail:3.1.3、为接口实例化同样可以通过对象多态性完成接口对象的实例化操作。interface
12、 Demopublic String INFO = “Hello World“ ;public void print() ; ;class DemoImpl implements Demo public void print()System.out.println(INFO) ;public class CaseDemo03 public static void main(String args)Demo demo = new DemoImpl() ;demo.print() ;3.1.4、接口的使用 制定标准(理解)电脑上有 USB 接口,只要是 USB 设备都可以向电脑上插入并使用。int
13、erface USB / 定义好了一个标准public void use() ; / 使用class Computer public static void plugIn(USB usb)usb.use() ;class Flash implements USB public void use()System.out.println(“使用 U 盘。“) ;class Print implements USB private String name ;public Print(String name)this.name = name ;public void use()System.out.p
14、rintln(“欢迎使用“ + this.name + “牌打印机! “) ;System.out.println(“开始打印!“) ;北京 MLDN 软件实训中心 联系电话:010-51283346第(6)页 共(31)页 E-Mail:;public class CaseDemo04 public static void main(String args)Computer.plugIn(new Flash() ;Computer.plugIn(new Print(“HP“) ;从实际的应用来看,接口主要有以下三大使用:1、 制定标准;2、 表示能力;3、 将远程方法的操作视图暴露给客户端。
15、3.1.5、接口的使用 工厂设计模式下面先来观察以下的一段代码:interface Fruitpublic void eat() ;class Apple implements Fruit public void eat()System.out.println(“吃苹果。“) ;class Orange implements Fruit public void eat()System.out.println(“吃橘子。“) ;public class CaseDemo05 public static void main(String args)Fruit f = new Orange() ;f
16、.eat() ;观察以上代码中存在的问题。现在的程序中可以发现,在主方法(客户端)上,是通过关键字 new 直接为接口进行实例化,也就是说以后在使用的时候如果要不更改主方法的话,则主方法中永远只能使用一个类,这样的耦合度太深了。回顾:Java 的可移植性原理:*.class JVM OS。原本可以直接由 A B 的情况,中间加入了 C:A C B。interface Fruitpublic void eat() ;北京 MLDN 软件实训中心 联系电话:010-51283346第(7)页 共(31)页 E-Mail:class Apple implements Fruit public voi
17、d eat()System.out.println(“吃苹果。“) ;class Orange implements Fruit public void eat()System.out.println(“吃橘子。“) ;class Factory public static Fruit getInstance(String className)Fruit f = null ;if(“apple“.equals(className)f = new Apple() ;if(“orange“.equals(className)f = new Orange() ;return f ;public cl
18、ass CaseDemo06 public static void main(String args)Fruit f = Factory.getInstance(args0) ;f.eat() ;此时,中间加入了一个过渡端(Factory) ,那么都通过过渡端找到接口的实例,这样的设计称为工厂设计,以后扩充子类的时候修改工厂即可:即:某一局部的修改不影响其他环境。3.1.6、接口的使用 代理设计模式现在,观察以下一种情况:一个代理人员可以代表一个真实的操作人员进行某些操作,但是两者的核心目的就是讨债。interface Subjectpublic void give() ;class Real
19、Subject implements Subjectpublic void give()System.out.println(“真正的讨债者:还我的钱。“) ;北京 MLDN 软件实训中心 联系电话:010-51283346第(8)页 共(31)页 E-Mail:class ProxySubject implements Subject private Subject sub ; / 设置代理人public ProxySubject(Subject sub)this.sub = sub ;public void before()System.out.println(“准备刀子,绳索,毒药。 。
20、 。“) ;public void give()this.before() ;this.sub.give() ; / 真实主题this.after() ;public void after()System.out.println(“跑路了。 。 。“) ;public class CaseDemo07 public static void main(String args)Subject s = new ProxySubject(new RealSubject() ;s.give() ;在此设计之中可以发现,真实主题完成具体的业务操作,而代理主题将完成与真实主题有关的其他的操作。3.1.7、接
21、口的使用 适配器设计(理解)在正常情况下,一个接口的子类肯定是要覆写一个接口中的全部抽象方法。那么有没有一种可能性,通过代码的变更,让一个子类可以有选择性的来覆写自己所需要的抽象方法呢?从概念上讲这样肯定不合适,所以中间就想一想加入一个过渡端,但是这个过渡端又不能直接使用。interface Funpublic void printA() ;public void printB() ;public void printC() ;abstract class FunAdapter implements Fun public void printA()public void printB()pub
22、lic void printC();class Demo extends FunAdapter public void printA()System.out.println(“Hello World!“) ;北京 MLDN 软件实训中心 联系电话:010-51283346第(9)页 共(31)页 E-Mail:;一般在进行图形界面的开发中才会使用到适配器的设计思路。3.1.8、抽象类和接口的区别(背下来)接口和抽象类从使用上看非常的相似,那么下面通过以下的表格对两者进行区分:No. 比较 抽象类 接口1 关键字 使用 abstract class 声明 使用 interface 声明2 定义
23、包含一个抽象方法的类 抽象方法和全局常量的集合3 组成 属性、方法、构造、常量、抽象方法 全局常量、抽象方法4 权限 抽象方法的权限可以任意 只能是 public 权限5 使用 通过 extends 关键字继承抽象类 通过 implements 关键字实现接口6 局限 抽象类存在单继承局限 没有此局限,一个子类可以实现多个接口7 顺序 一个子类只能先继承抽象类再实现多个接口模板设计 工厂设计、代理设计8 设计模式两者联合可以完成一个适配器设计9 实际作用 只能做一个模板使用 作为标准、表示能力10 使用 两者没有什么本质的区别,但是从实际上来看,如果一个程序中抽象类和接口都可以使用的话,则一定
24、要优先考虑接口,因为接口可以避免单继承所带来的局限。11 实例化 都是依靠对象多态性,通过子类进行对象实例化的观察一下以下程序的执行结果:abstract class Demo public Demo()this.print() ;public abstract void print() ;class DemoImpl extends Demo private int x = 10 ;public DemoImpl(int x)this.x = x ;public void print()System.out.println(“x = “ + this.x) ;public class Cas
25、eDemo09 public static void main(String args)new DemoImpl(100) ;本程序的答案是 0,这道程序完全体现了子类对象实例化的过程。北京 MLDN 软件实训中心 联系电话:010-51283346第(10)页 共(31)页 E-Mail:3.2、匿名内部类(重点)匿名内部类是在以后的框架开发中经常使用到的一种概念,但是对于一些简单的开发确实是暂时不用。匿名内部类是在内部类及抽象类和接口的基础上发展起来的。interface Xpublic void print() ;class A implements X public void prin
26、t()System.out.println(“Hello World!“) ;class Demo public void fun(X x)x.print() ;public void hello()this.fun(new A() ;public class NoInner public static void main(String args)new Demo().hello() ;此时有一个新的问题,如果现在的 A 类只使用一次的话,那么有必要将其定义成一个具体的类吗?此时,就可以通过匿名内部类来解决此问题。interface Xpublic void print() ;class De
27、mo public void fun(X x)x.print() ;public void hello(final String info)this.fun(new X()public void print()System.out.println(info) ;) ;public class NoInner 北京 MLDN 软件实训中心 联系电话:010-51283346第(11)页 共(31)页 E-Mail:public static void main(String args)new Demo().hello(“Hello World!“) ;3.3、包装类( 重点)在 Java 中一直
28、提倡:一切皆对象。但是,此时一个问题就出现了,基本数据类型不是类,所以为了可以让基本数据类型变为类的形式进行操作的话,在 Java 中引入了包装类的概念,可以通过包装类完成基本数据类型的封装。在 Java 中一共定义了八种基本数据类型:int (Integer ) 、char(Character ) 、float(Float) 、double(Double) 、long(Long) 、short(Short) 、byte(Byte) 、boolean (Boolean )但是,需要注意的是,以上的八种包装类也分为两种类型: 数值型:指的是 Number 的子类,有:Integer 、Float
29、、Double、Long 、Short、Byte 对象型:指的是 Object 的子类,有:Character、Boolean在 Number 类中规定了一系列的 xxxValue()方法,可以将被包装的数字取出,变回基本数据类型。3.3.1、装箱及拆箱装箱:将一个基本数据类型变为包装类称为装箱操作,装箱的方法由各个子类完成拆箱:将一个包装类变回基本数据类型,称为拆箱操作,转换的方法由 Number 类提供。范例:以整型为例public class WrapperDemo01 public static void main(String args)int x1 = 10 ; / 基本数据类型I
30、nteger temp = new Integer(x1) ; / 装箱int x2 = temp.intValue() ; / 拆箱System.out.println(x2 * x2) ;范例:以浮点型为例public class WrapperDemo02 public static void main(String args)float x1 = 10.3f ;Float temp = new Float(x1) ;float x2 = temp.floatValue() ;System.out.println(x2 * x2) ;对于以上的操作,实际上也是随着版本的不同而有所不同的,
31、上面的代码是在 JDK 1.4 的时候使用的,所有的操作必须进行手工的装箱及拆箱操作,而且所有的包装类是不能直接进行各种计算的,但是到了 JDK 1.5 之后,Java 向.NET学习,增加了自动装箱和拆箱的操作,而且所有的包装类可以自动的执行数学计算的功能。范例:观察自动装箱和拆箱的操作北京 MLDN 软件实训中心 联系电话:010-51283346第(12)页 共(31)页 E-Mail:public class WrapperDemo03 public static void main(String args)Float temp = 10.3f ; / 自动装箱/ Object obj
32、 = 10.3f ; / 基本 包装 变为 Object/ 先自动拆箱,之后计算再装箱System.out.println(temp * temp) ;float x = temp ; / 自动拆箱;3.3.2、数据转换包装类的最大好处是可以将字符串中的数据变为基本数据类型,例如:将一个字符串变为 int 或者是 float 型的数据,使用的方法是各个包装类中提供的:static 数据类型 parse 数据类型() 。public class WrapperDemo04 public static void main(String args)String str = “133“ ;int x
33、= Integer.parseInt(str) ; / 将字符串边回基本数据类型System.out.println(x * x) ;但是需要注意的是,在使用以上方法操作的时候一定要小心,字符串中的内容必须完全由数字组成。public class WrapperDemo05 public static void main(String args)String str = “133“ ;float x = Float.parseFloat(str) ; / 将字符串边回基本数据类型System.out.println(x * x) ;3.3.3、题目现在要求可以设计一个表示坐标的操作类(Poin
34、t) ,此类中可以分别表示以下的三种坐标: 第一种: x=10, y=30 第二种: x=10.3,y=30.9 第三种: x=“东经 110 度“,y=“北纬 200 度“问,此类该如何设计?由于现在存在了三种数据类型的数据,所以为了保证接收,只能通过 Object 接收: int Integer Object float Float Object String Objectclass Point private Object x ;北京 MLDN 软件实训中心 联系电话:010-51283346第(13)页 共(31)页 E-Mail:private Object y ;public vo
35、id setX(Object x)this.x = x ;public void setY(Object y)this.y = y ;public Object getX()return this.x ;public Object getY()return this.y ;下面分别通过不同的数据类型对程序进行验证:1、 使用 int 型public class PointDemo public static void main(String args)Point p = new Point() ;p.setX(10) ; / int Integer Objectp.setY(30) ; / i
36、nt Integer Objectint x = (Integer) p.getX() ; / Object Integer intint y = (Integer) p.getY() ; / Object Integer intSystem.out.println(“X 的坐标:“ + x) ;System.out.println(“Y 的坐标:“ + y) ;2、 使用 float 型public class PointDemo public static void main(String args)Point p = new Point() ;p.setX(10.3f) ;p.setY(
37、30.5f) ;float x = (Float) p.getX() ;float y = (Float) p.getY() ;System.out.println(“X 的坐标:“ + x) ;System.out.println(“Y 的坐标:“ + y) ;3、 使用 String 型public class PointDemo public static void main(String args)Point p = new Point() ;p.setX(“东经 120 度“) ;北京 MLDN 软件实训中心 联系电话:010-51283346第(14)页 共(31)页 E-Mail
38、:p.setY(“北纬 100 度“) ;String x = (String) p.getX() ;String y = (String) p.getY() ;System.out.println(“X 的坐标:“ + x) ;System.out.println(“Y 的坐标:“ + y) ;现在已经解决了本题目的要求,按照之前所学,现在肯定是最合理的解决方案,但是,本程序又存在了一个安全隐患,因为所有的类型都使用 Object 进行接收,那么有没有一种可能,将 X 的坐标设置成了整型,而 Y 的坐标设置成了字符串?public class PointDemo public static
39、void main(String args)Point p = new Point() ;p.setX(100) ;p.setY(“北纬 100 度“) ;String x = (String) p.getX() ;String y = (String) p.getY() ;System.out.println(“X 的坐标:“ + x) ;System.out.println(“Y 的坐标:“ + y) ;那么,对于以上的问题,在 JDK 1.5 之后就可以解决了,因为 JDK 1.5 有一个最大的特点,就是加入了泛型的操作。class Point private T x ;private
40、T y ;public void setX(T x)this.x = x ;public void setY(T y)this.y = y ;public T getX()return this.x ;public T getY()return this.y ;程序中的“”就表示的是一种类型,只是这种类型现在属于未知的,在类使用的时候设置类型。public class PointDemo public static void main(String args)Point p = new Point() ;p.setX(“东经 100 度“) ;北京 MLDN 软件实训中心 联系电话:010-5
41、1283346第(15)页 共(31)页 E-Mail:p.setY(“北纬 100 度“) ;String x = p.getX() ;String y = p.getY() ;System.out.println(“X 的坐标:“ + x) ;System.out.println(“Y 的坐标:“ + y) ;泛型中的类型可以由外部决定,但是在设置基本数据类型的时候,只能使用包装类。public class PointDemo public static void main(String args)Point p = new Point() ;p.setX(10) ;p.setY(20)
42、;int x = p.getX() ;int y = p.getY() ;System.out.println(“X 的坐标:“ + x) ;System.out.println(“Y 的坐标:“ + y) ;设置泛型之后,程序更加安全了,可以避免掉类转换异常的出现。3.4、泛型(理解)JDK 1.5 之后增加了很多的新特性,其中有三项是最重要的新特性:泛型、枚举、 Annotation,但是这三项中并不能作为程序开发的重点。泛型作为一个较大的新特性,在类库中使用较多,但是一般都是结合类集框架来看的,本次只是将一些基本的语法进行讲解,先来观察基本概念。3.4.1、泛型的作用泛型的主要目的是为了
43、解决在进行类转换过程中发生的类转换异常的问题,用于处理安全隐患的。所以为了避免掉ClassCastException 在 JDK 1.5 之后增加了泛型的操作,泛型的具体含义就是一个类中的某些属性的操作类型由使用此类的时候决定。在设置烦型的时候是通过“”的形式设置的,这里只是设置了一个标记,以后会根据设置的情况换成不同的类型,但是需要注意的是,为了保证 JDK 1.5 之前代码的使用正常,所以在泛型中也可以不设置类型,如果不设置的话,称为擦除泛型,将全部使用 Object 进行接收。当然,也可以同时设置多个泛型类型,例如:class Point 3.4.2、通配符泛型确实可以保证程序避免安全隐
44、患问题,但是程序中一旦使用了泛型之后对于引用传递上又会存在问题。北京 MLDN 软件实训中心 联系电话:010-51283346第(16)页 共(31)页 E-Mail:class Info private T content ;public void setContent(T content)this.content = content ;public T getContent()return this.content ;public class GenDemo01 public static void main(String args)Info info = new Info() ;inf
45、o.setContent(“Hello World“) ;fun(info) ;public static void fun(Info temp)System.out.println(temp.getContent() ;以上的程序非常的容易,但是这个时候有一个问题出现了,如果现在设置的泛型类型不是 String 呢?由于 fun()方法上设置的 Info 只能接收 String,所以肯定无法传递,那么如果现在在 fun()方法中不写呢?public class GenDemo01 public static void main(String args)Info info = new Info
46、() ;info.setContent(30) ;fun(info) ;public static void fun(Info temp)System.out.println(temp.getContent() ;如果这样写的话,则意味着,以后可以通过 fun()方法向 Info 的对象中设置任意样的内容。public static void fun(Info temp)temp.setContent(“Hello“) ;System.out.println(temp.getContent() ;这种操作是存在安全隐患的。那么如果写成如下的形式?public static void fun(I
47、nfo temp)System.out.println(temp.getContent() ;这种做法肯定没意义,而且不能编译通过,那么该如何修饰呢?此时关键性的问题,是如何解决调用设置的问题,而不是取得属性输出的问题,所以说在泛型中增加了一个“?”表示的是接收所有的泛型类型,而且一旦接收之后只能取得,不能设置。public class GenDemo01 北京 MLDN 软件实训中心 联系电话:010-51283346第(17)页 共(31)页 E-Mail:public static void main(String args)Info info = new Info() ;info.setContent(30) ;fun(info) ;public static void fun(Info temp)System.out.println(temp.getContent() ;但是一个新的问题又出现了,如果现在的 Info 中的 content 属性只能是数字,不能是其他的