instanceof关键字
需要掌握的要点:
掌握instanceof关键字的作用以及使用时机。
可以使用instanceof对对象的转型进行安全验证。
具体内容:
在Java中可以使用instanceof关键字判断一个对象到底是哪个类的实例。
对象 instanceof 类 —>返回boolean类型
代码验证如下:
class A{ // 定义类A
public void fun1(){ // 定义fun1()方法
System.out.println("A --> public void fun1(){}") ;
}
public void fun2(){
this.fun1() ; // 调用fun1()方法
}
};
class B extends A{
public void fun1(){ // 此方法被子类覆写了
System.out.println("B --> public void fun1(){}") ;
}
public void fun3(){
System.out.println("B --> public void fun3(){}") ;
}
};
public class InstanceofDemo01{
public static void main(String asrgs[]){
A a1 = new B() ; // 通过向上转型实例化对象
System.out.println("A a1 = new B():" + (a1 instanceof A)) ;
System.out.println("A a1 = new B():" + (a1 instanceof B)) ;
A a2 = new A() ; // 通过向上转型实例化对象
System.out.println("A a2 = new A():" + (a2 instanceof A)) ;
System.out.println("A a2 = new A():" + (a2 instanceof B)) ;
}
};
使用instanceof关键字可以做哪些事情?
从之前在对象多态性的研究代码中可以发现一个问题。
如果现在传入的实例是B类的实例,则需要调用fun3()方法,如果是C类则需要调用fun5方法。
class A{ // 定义类A
public void fun1(){ // 定义fun1()方法
System.out.println("A --> public void fun1(){}") ;
}
public void fun2(){
this.fun1() ; // 调用fun1()方法
}
};
class B extends A{
public void fun1(){ // 此方法被子类覆写了
System.out.println("B --> public void fun1(){}") ;
}
public void fun3(){
System.out.println("B --> public void fun3(){}") ;
}
};
class C extends A{
public void fun1(){ // 此方法被子类覆写了
System.out.println("C --> public void fun1(){}") ;
}
public void fun5(){
System.out.println("C --> public void fun5(){}") ;
}
};
public class InstanceofDemo02{
public static void main(String asrgs[]){
fun(new B()) ;
fun(new C()) ;
}
public static void fun(A a){
a.fun1() ;
if(a instanceof B){
B b = (B) a ;
b.fun3() ;
}
if(a instanceof C){
C c = (C) a ;
c.fun5() ;
}
}
};
在开发中一定要注意,对于向下转型操作最好增加验证,以保证转型时不会发生ClassCastException。
如果现在要增加新的子类,则肯定要修改fun方法,这样一来程序就失去了灵活性,所以在程序的开发中重点的设计应该放在父类上,只要父类设计足够合理,则会带来很大的方便。
而且在开发中一定要注意以下一点:
一个类永远不要去继承一个已经实现好的类。而只能继承抽象类或实现接口。
instanceof总结:
1、instanceof用于判断一个对象是否是某个类的实例。
2、在对象向下转型之前最好使用instanceof关键字进行验证。
抽象类与接口的应用
需要掌握的有关内容如下:
掌握抽象类以及接口的实例化操作。
掌握模板设计的作用。
掌握工厂设计模式的作用。
掌握代理设计模式的作用。
掌握适配器设计模式的作用。
掌握抽象类与抽象接口的使用区别。
为抽象类与接口实例化:
在Java中可以通过对象多态性,为抽象类和接口实例化这样再使用抽象类和接口的时候就可以调用被子类中所覆写过的方法了。
之所以抽象类和接口不能直接实例化,是因为其内部包含了各个抽象方法,抽象方法本身都是未实现的方法,所以无法调用。
通过对象的多态性可以发现,子类发生了向上转型关系之后,所调用的全部方法都是被覆写过的方法。
abstract class A{ // 定义抽象类A
public abstract void print() ; // 定义抽象方法print()
};
class B extends A { // 定义子类,继承抽象类
public void print(){ // 覆写抽象方法
System.out.println("Hello World!!!") ;
}
};
public class AbstractCaseDemo01{
public static void main(String args[]){
A a = new B() ; // 通过子类为抽象类实例化
a.print() ;
}
};
可以继续使用此概念,为一个接口实例化。
interface A{ // 定义抽象类A
public abstract void print() ; // 定义抽象方法print()
};
class B implements A { // 定义子类,继承抽象类
public void print(){ // 覆写抽象方法
System.out.println("Hello World!!!") ;
}
};
public class AbstractCaseDemo01{
public static void main(String args[]){
A a = new B() ; // 通过子类为抽象类实例化
a.print() ;
}
};
证明,如果要使用抽象类或接口,则只能按照以上的操作完成。
抽象类的实际应用——模板设计
场景如下:假设人分为学生和工人,学生和工人都可以说话,但是学生和工人说话的内容是不一样的,也就是说说话这个功能应该是一个具体的功能,而说话的内容就要由学生和工人来决定了。所以此时就可以使用抽象类来实现这种场景。
abstract class Person{
private String name ; // 定义name属性
private int age ; // 定义age属性
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
public void say(){ // 人说话是一个具体的功能
System.out.println(this.getContent()) ; // 输出内容
}
public abstract String getContent() ; // 说话的内容由子类决定
};
class Student extends Person{
private float score ;
public Student(String name,int age,float score){
super(name,age) ; // 调用父类中的构造方法
this.score = score ;
}
public String getContent(){
return "学生信息 --> 姓名:" + super.getName() +
";年龄:" + super.getAge() +
";成绩:" + this.score ;
}
};
class Worker extends Person{
private float salary ;
public Worker(String name,int age,float salary){
super(name,age) ; // 调用父类中的构造方法
this.salary = salary ;
}
public String getContent(){
return "工人信息 --> 姓名:" + super.getName() +
";年龄:" + super.getAge() +
";工资:" + this.salary ;
}
};
public class AbstractCaseDemo02{
public static void main(String args[]){
Person per1 = null ; // 声明Person对象
Person per2 = null ; // 声明Person对象
per1 = new Student("张三",20,99.0f) ; // 学生是一个人
per2 = new Worker("李四",30,3000.0f) ; // 工人是一个人
per1.say() ; // 学生说学生的话
per2.say() ; // 工人说工人的话
}
};
接口的实际应用——制定标准
接口在实际中更多的作用是用来制定标准的。比如说:U盘和打印机都可以插在电脑上使用,这是因为它们都实现了USB接口,对于电脑来说只要是符合了USB接口标准的设备就都可以插进来。
interface USB{ // 定义了USB接口
public void start() ; // USB设备开始工作
public void stop() ; // USB设备结束工作
}
class Computer{
public static void plugin(USB usb){ // 电脑上可以插入USB设备
usb.start() ;
System.out.println("=========== USB 设备工作 ========") ;
usb.stop() ;
}
};
class Flash implements USB{
public void start(){ // 覆写方法
System.out.println("U盘开始工作。") ;
}
public void stop(){ // 覆写方法
System.out.println("U盘停止工作。") ;
}
};
class Print implements USB{
public void start(){ // 覆写方法
System.out.println("打印机开始工作。") ;
}
public void stop(){ // 覆写方法
System.out.println("打印机停止工作。") ;
}
};
public class InterfaceCaseDemo02{
public static void main(String args[]){
Computer.plugin(new Flash()) ;
Computer.plugin(new Print()) ;
}
};
深入研究的话,接口实际上还表示将方法的视图暴漏给远程的客户端。
工厂设计模式
工厂设计模式,是在Java开发中最常使用的一种设计模式。
interface Fruit{ // 定义一个水果接口
public void eat() ; // 吃水果
}
class Apple implements Fruit{
public void eat(){
System.out.println("** 吃苹果。") ;
}
};
class Orange implements Fruit{
public void eat(){
System.out.println("** 吃橘子。") ;
}
};
public class InterfaceCaseDemo03{
public static void main(String args[]){
Fruit f = new Apple() ; // 实例化接口
f.eat() ;
}
};
这样的代码可以使用吗?有问题吗?
分析:主方法:应该表示一个客户端,主方法的代码越少越好。此时,直接在主方法中指定了要操作的子类,如果要更换子类,则肯定要修改客户端。就表示跟特定的子类紧密耦合在一起了。
JVM原理:程序—>JVM—>操作系统。
过渡端在程序中就称为工厂设计。
interface Fruit{ // 定义一个水果接口
public void eat() ; // 吃水果
}
class Apple implements Fruit{
public void 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 class InterfaceCaseDemo05{
public static void main(String args[]){
Fruit f = Factory.getInstance(args[0]) ; // 实例化接口
if(f!=null){ // 判断是否取得实例
f.eat() ;
}
}
};
代理模式
设计模式—代理设计
代理设计也是在Java开发中使用较多的一种设计模式,所谓的代理设计就是指一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理,就好比在生活中经常使用到的代理上网那样,客户通过网络代理连接网络,由代理服务器完成用户权限,访问限制等上网操作相关的操作。
分析结果:不管是代理操作也好,真实操作也好,其共同目的就是上网,所以用户关心的只是如何上网,至于里面是如何操作的用户并不关心。
interface Network{
public void browse() ; // 浏览
}
class Real implements Network{
public void browse(){
System.out.println("上网浏览信息") ;
}
};
class Proxy implements Network{
private Network network ; // 代理对象
public Proxy(Network network){
this.network = network ;
}
public void check(){
System.out.println("检查用户是否合法。") ;
}
public void browse(){
this.check() ;
this.network.browse() ; // 调用真实的主题操作
}
};
public class ProxyDemo{
public static void main(String args[]){
Network net = null ;
net = new Proxy(new Real()) ;// 指定代理操作
net.browse() ; // 客户只关心上网浏览一个操作
}
};
适配器设计
适配器设计主要在Java的图形界面上使用最多。
设计模式——适配器设计
对于Java程序来说,如果一个类要实现一个接口,则肯定要覆写此接口中的全部抽象方法,那么如果,此时一个接口中定义的抽象方法过多,但是在子类中又用不到这么多的抽象方法,则肯定很麻烦,所以此时就需要一个中间的过渡,但是此过渡又不希望被直接使用,所以将此过渡类定义成抽象类最合适,即一个接口首先被一个抽象类(此抽象类通常被称为适配器类),并在此抽象类中实现若干方法(方法体为空)则以后的子类直接继承此抽象类,就可以有选择的覆写所需要的方法。必须实现的方法在适配器中定义成抽象方法,可选择实现的方法定义成方法体为空的方法即可。
interface Window{ // 定义Window接口,表示窗口操作
public void open() ; // 打开
public void close() ; // 关闭
public void activated() ; // 窗口活动
public void iconified() ; // 窗口最小化
public void deiconified();// 窗口恢复大小
}
abstract class WindowAdapter implements Window{
public void open(){} ; // 打开
public void close(){} ; // 关闭
public void activated(){} ; // 窗口活动
public void iconified(){} ; // 窗口最小化
public void deiconified(){};// 窗口恢复大小
};
class WindowImpl extends WindowAdapter{
public void open(){
System.out.println("窗口打开。") ;
}
public void close(){
System.out.println("窗口关闭。") ;
}
};
public class AdapterDemo{
public static void main(String args[]){
Window win = new WindowImpl() ;
win.open() ;
win.close() ;
}
};
此种设计思路,在Java的图形界面编程上使用的非常多,但是在JavaEE的开发中并不常见。
内部类的拓展
实际上抽象类中也可以包含一个接口。
abstract class A{ // 定义抽象类
public abstract void printA() ; // 抽象方法
interface B{ // 定义内部接口
public void printB() ; // 定义抽象方法
}
};
class X extends A{ // 继承抽象类
public void printA(){
System.out.println("HELLO --> A") ;
}
class Y implements B{ // 定义内部类实现内部接口
public void printB(){
System.out.println("HELLO --> B") ;
}
};
};
public class InnerExtDemo01{
public static void main(String args[]){
A.B b = new X().new Y() ;
b.printB() ;
}
};
反之,在一个接口中也可以定义一个抽象类。
interface A{ // 定义接口
public void printA() ; // 抽象方法
abstract class B{ // 定义内部抽象类
public abstract void printB() ; // 定义抽象方法
}
};
class X implements A{ // 实现接口
public void printA(){
System.out.println("HELLO --> A") ;
}
class Y extends B{ // 继承抽象类
public void printB(){
System.out.println("HELLO --> B") ;
}
};
};
public class InnerExtDemo02{
public static void main(String args[]){
A.B b = new X().new Y() ;
b.printB() ;
}
};
但是从实际的开发角度上将,此种设计并不常见,因为代码的结构有些混乱了。
重要提示:一个类永远不要去继承一个已经实现好的类,要么继承抽象类,要么实现接口,如果接口和抽象类同时都可以使用的话,那么优先使用接口,可以避免单继承。
总结:
1、抽象类和接口的实例化:通过对象多态性。
2、抽象类表示一个模板,接口制定的是一个标准。
3、常见的设计模式:模板设计,工厂设计、代理设计、适配器设计。