文档版本 | 开发工具 | 测试平台 | 工程名字 | 日期 | 作者 | 备注 |
---|---|---|---|---|---|---|
V1.0 | 2016.02.29 | lutianfei | none |
[TOC]
final 关键字
final关键字,可以修饰
类
,成员变量
,成员方法
。-
特点:
- 修饰的
类
,类不能被继承 - 修饰的
变量
,变量就变成了常量,只能被赋值一次 - 修饰的
方法
,方法不能被重写
- 修饰的
final关键字面试题
-
Eg1: final修饰局部变量
- 在方法内部,该变量不可以被改变
- 在方法声明上,分为
基本类型
和引用类型
作为参数的情况- 基本类型,是值不能被改变
- 引用类型,是地址值不能被改变,但是该对象堆内存的值可以改变。
-
Eg2: final修饰变量的初始化时机
- 在对象构造完毕前即可
class Student {
int age = 10;
}
class FinalTest {
public static void main(String[] args) {
//局部变量是基本数据类型
int x = 10;
x = 100;
System.out.println(x);
final int y = 10;
//无法为最终变量y分配值
//y = 100;
System.out.println(y);
System.out.println("--------------");
//局部变量是引用数据类型
Student s = new Student();
System.out.println(s.age);
s.age = 100;
System.out.println(s.age);
System.out.println("--------------");
final Student ss = new Student();
System.out.println(ss.age);
ss.age = 100;
System.out.println(ss.age);
//重新分配内存空间
//无法为最终变量ss分配值
ss = new Student();
}
}
多态
多态概述
- 某一个事物,在不同时刻表现出来的不同状态。
- 举例:
- 猫可以是猫的类型。猫 m = new 猫();
- 同时猫也是动物的一种,也可以把猫称为动物。
- 动物 d = new 猫();
- 再举一个例子:水在不同时刻的状态
- 举例:
- 多态前提和体现
- 有继承关系
- 有方法重写
- 有父类引用指向子类对象
- Fu f = new Zi();
多态的分类:
- 具体类多态:
- class Fu{}
- class Zi extends Fu{}
- Fu f = new Zi();
- 抽象类多态:
- abstract class Fu{}
- class Zi extends Fu{}
- Fu f = new Zi();
- 接口多态:
- interface Fu{}
- class Zi implements Fu{}
- Fu f = new Zi();
多态中的成员访问特点:
A:
成员变量
:编译看左边,运行看左边。B:
构造方法
:创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。C:
成员方法
: 编译看左边,运行看右边。由于成员方法存在方法重写,所以它运行看右边。-
D:
静态方法
:编译看左边,运行看左边。- (静态和类相关,算不上重写,所以,访问还是左边的)
/*
多态:同一个对象(事物),在不同时刻体现出来的不同状态。
举例:
猫是猫,猫是动物。
水(液体,固体,气态)。
多态的前提:
A:要有继承关系。
B:要有方法重写。
其实没有也是可以的,但是如果没有这个就没有意义。
动物 d = new 猫();
d.show();
动物 d = new 狗();
d.show();
C:要有父类引用指向子类对象。
父 f = new 子();
*/
class Fu {
public int num = 100;
public void show() {
System.out.println("show Fu");
}
public static void function() {
System.out.println("function Fu");
}
}
class Zi extends Fu {
public int num = 1000;
public int num2 = 200;
public void show() {
System.out.println("show Zi");
}
public void method() {
System.out.println("method zi");
}
public static void function() {
System.out.println("function Zi");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
//要有父类引用指向子类对象。
//父 f = new 子();
Fu f = new Zi();
System.out.println(f.num);
//找不到符号
//System.out.println(f.num2);
f.show();
//找不到符号
//f.method();
f.function();
}
}
/*
* 运行结果:
100
show Zi
function Fu
*/
多态的优缺点
-
多态的好处
- 提高了程序的维护性(由继承保证)
- 提高了程序的扩展性(由多态保证)
-
多态的弊端
- 父类不能访问子类特有功能
-
如何才能访问子类的特有功能呢?
- 创建子类对象,调用方法即可。(然而很多时候不合理,且太占内存)
-
向下转型
:把父类的引用强制转换为子类的引用。- Zi z = (Zi)f; //要求该f必须是能够转换为Zi的
现象: 子可以当做父使用,父不能当作子使用。
多态中的转型问题
- 向上转型
- 从子到父
- 父类引用指向子类对象
- 向下转型
- 从父到子
- 父类引用转为子类对象
- 孔子装爹案例
//多态的问题理解:
class 孔子爹 {
public int age = 40;
public void teach() {
System.out.println("讲解JavaSE");
}
}
class 孔子 extends 孔子爹 {
public int age = 20;
public void teach() {
System.out.println("讲解论语");
}
public void playGame() {
System.out.println("英雄联盟");
}
}
//Java培训特别火,很多人来请孔子爹去讲课,这一天孔子爹被请走了
//但是还有人来请,就剩孔子在家,价格还挺高。孔子一想,我是不是可以考虑去呢?
//然后就穿上爹的衣服,带上爹的眼睛,粘上爹的胡子。就开始装爹
//向上转型
孔子爹 k爹 = new 孔子();
//到人家那里去了
System.out.println(k爹.age); //40
k爹.teach(); //讲解论语
//k爹.playGame(); //这是儿子才能做的,一做就报错!
//讲完了,下班回家了
//脱下爹的装备,换上自己的装备
//向下转型
孔子 k = (孔子) k爹;
System.out.println(k.age); //20
k.teach(); //讲解论语
k.playGame(); //英雄联盟
-
多态中的对象变化内存图
- 多态练习:猫狗案例
class Animal {
public void eat(){
System.out.println("吃饭");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("狗吃肉");
}
public void lookDoor() {
System.out.println("狗看门");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
public void playGame() {
System.out.println("猫捉迷藏");
}
}
class DuoTaiTest {
public static void main(String[] args) {
//定义为狗
Animal a = new Dog();
a.eat();
System.out.println("--------------");
//还原成狗
Dog d = (Dog)a;
d.eat();
d.lookDoor();
System.out.println("--------------");
//变成猫
a = new Cat();
a.eat();
System.out.println("--------------");
//还原成猫
Cat c = (Cat)a;
c.eat();
c.playGame();
System.out.println("--------------");
}
}
- 不同地方饮食文化不同的案例
class Person {
public void eat() {
System.out.println("吃饭");
}
}
class SouthPerson extends Person {
public void eat() {
System.out.println("炒菜,吃米饭");
}
public void jingShang() {
System.out.println("经商");
}
}
class NorthPerson extends Person {
public void eat() {
System.out.println("炖菜,吃馒头");
}
public void yanJiu() {
System.out.println("研究");
}
}
class DuoTaiTest2 {
public static void main(String[] args) {
//测试
//南方人
Person p = new SouthPerson();
p.eat();
System.out.println("-------------");
SouthPerson sp = (SouthPerson)p;
sp.eat();
sp.jingShang();
System.out.println("-------------");
//北方人
p = new NorthPerson();
p.eat();
System.out.println("-------------");
NorthPerson np = (NorthPerson)p;
np.eat();
np.yanJiu();
}
}
/*
运行结果:
炒菜,吃米饭
-------------
炒菜,吃米饭
经商
-------------
炖菜,吃馒头
-------------
炖菜,吃馒头
研究
*/
多态中继承练习
-
继承的时候:
- 子类中有和父类中一样的方法,叫
重写
。 - 子类中没有父亲中出现过的方法,方法就被
继承
过来了。
- 子类中有和父类中一样的方法,叫
Eg:(不太理解)
/*
多态的成员访问特点:
方法:编译看左边,运行看右边。
继承的时候:
子类中有和父类中一样的方法,叫重写。
子类中没有父亲中出现过的方法,方法就被继承过来了。
*/
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
/*
public void show() {
show2();
}
*/
public void show2() {
System.out.println("爱");
}
}
class C extends B {
public void show() {
super.show();
}
public void show2() {
System.out.println("你");
}
}
public class DuoTaiTest4 {
public static void main(String[] args) {
A a = new B();
a.show();
B b = new C();
b.show();
}
}
// 运行结果:
//爱
//你
抽象类
抽象类概述
- 动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫,狗才是具体的动物。同理,我们也可以推想,不同的动物吃的东西应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。在Java中,一个没有
方法体
(连大括号也没有)的方法应该定义为抽象方法
,而类中如果有抽象方法
,该类必须定义为抽象类
。
抽象类特点
-
抽象类
和抽象方法
必须用abstract
关键字修饰- 格式
- abstract class 类名 {}
- public abstract void eat();
- 格式
-
抽象类
不一定有抽象方法
,有抽象方法
的类一定是抽象类
- 抽象类不能实例化(抽象类如何实例化呢?)
- 按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
- 抽象类有
构造方法
,其作用是为了用于子类访问父类数据的初始化。
- 抽象类的
子类
- 要么是抽象类
- 要么重写抽象类中的所有
抽象方法
//abstract class Animal //抽象类的声明格式
abstract class Animal {
//抽象方法
//public abstract void eat(){} //空方法体,这个会报错。抽象方法不能有主体
public abstract void eat();
public Animal(){}
}
//子类是抽象类
abstract class Dog extends Animal {}
//子类是具体类,重写抽象方法
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
}
class AbstractDemo {
public static void main(String[] args) {
//创建对象
//Animal是抽象的; 无法实例化
//Animal a = new Animal();
//通过多态的方式
Animal a = new Cat();
a.eat();
}
}
抽象类的成员特点
- 成员变量
- 可以是变量
- 也可以是常量
- 构造方法
- 有构造方法,但是不能实例化
- 那么,构造方法的作用是什么呢?
- 用于子类访问父类数据的初始化
- 成员方法
- 可以有抽象方法 作用:限定子类必须完成某些动作
- 也可以有非抽象方法 提高代码复用性
- 抽象定义类练习:
//定义抽象的动物类
abstract class Animal {
//姓名
private String name;
//年龄
private int age;
public Animal() {}
public Animal(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//定义一个抽象方法
public abstract void eat();
}
//定义具体的狗类
class Dog extends Animal {
public Dog() {}
public Dog(String name,int age) {
super(name,age); //重要知识点!!!
}
public void eat() {
System.out.println("狗吃肉");
}
}
//定义具体的猫类
class Cat extends Animal {
public Cat() {}
public Cat(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("猫吃鱼");
}
}
//测试类
class AbstractTest {
public static void main(String[] args) {
//测试狗类
//具体类用法
//方式1:
Dog d = new Dog();
d.setName("旺财");
d.setAge(3);
System.out.println(d.getName()+"---"+d.getAge());
d.eat();
//方式2:
Dog d2 = new Dog("旺财",3);
System.out.println(d2.getName()+"---"+d2.getAge());
d2.eat();
System.out.println("---------------------------");
Animal a = new Dog();
a.setName("旺财");
a.setAge(3);
System.out.println(a.getName()+"---"+a.getAge());
a.eat();
Animal a2 = new Dog("旺财",3);
System.out.println(a2.getName()+"---"+a2.getAge());
a2.eat();
//练习:测试猫类
}
}
- 抽象教师类练习:
//定义抽象的老师类
abstract class Teacher {
//姓名
private String name;
//年龄
private int age;
public Teacher() {}
public Teacher(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//抽象方法
public abstract void teach();
}
//基础班老师类
class BasicTeacher extends Teacher {
public BasicTeacher(){}
public BasicTeacher(String name,int age) {
super(name,age);
}
public void teach() {
System.out.println("基础班老师讲解JavaSE");
}
}
//就业班老师类
class WorkTeacher extends Teacher {
public WorkTeacher(){}
public WorkTeacher(String name,int age) {
super(name,age);
}
public void teach() {
System.out.println("就业班老师讲解JavaEE");
}
}
class AbstractTest2 {
public static void main(String[] args) {
//具体的类测试,自己玩
//测试(多态)
//基础班老师
Teacher t = new BasicTeacher();
t.setName("刘意");
t.setAge(30);
System.out.println(t.getName()+"---"+t.getAge());
t.teach();
System.out.println("--------------");
t = new BasicTeacher("刘意",30);
System.out.println(t.getName()+"---"+t.getAge());
t.teach();
System.out.println("--------------");
//就业班老师
t = new WorkTeacher();
t.setName("林青霞");
t.setAge(27);
System.out.println(t.getName()+"---"+t.getAge());
t.teach();
System.out.println("--------------");
t = new WorkTeacher("林青霞",27);
System.out.println(t.getName()+"---"+t.getAge());
t.teach();
}
}
抽象类的几个小问题
- 一个类如果没有抽象方法,可以定义为抽象类?如果可以,有什么意义?
- 可以
- 禁止创建对象
-
abstract
不能和哪些关键字共存-
private
冲突 -
final
冲突 -
static
无意义(通过类名直接访问没有内容的方法体)
-
接口
接口概述
- 狗一般就是看门,猫一般就是作为宠物。但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的。所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。
所以,为了体现事物功能的扩展性,Java中就提供了接口
来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可。
接口特点
-
接口用关键字
interface
表示- 格式:interface 接口名 {}
-
类实现接口用
implements
表示- 格式:class 类名 implements 接口名 {}
-
接口不能实例化(接口如何实例化呢?)
- 按照多态的方式,由具体的子类实例化。其实这也是多态的一种,接口多态。
-
接口的实现类(子类):
-
抽象类
:实现接口,但意义不大 -
具体类
:重写接口中的所有抽象方法
-
-
补充:多态的三种形式
- 具体类多态(几乎没有)
- 抽象类多态(常用)
- 接口类多态(最常用 )
接口成员特点
-
成员变量
- 只能是
常量
- 默认修饰符 public static final
- 只能是
-
构造方法
- 没有,因为接口主要是扩展功能的,而没有具体存在。
- 所有的类都默认继承自一个类:Object。(类Object 是类层次结构的根类。每个类都使用Object作为超类)
-
成员方法
- 只能是抽象方法
- 默认修饰符 public abstract
类与类,类与接口以及接口与接口的关系
- 类与类
- 继承关系,只能单继承,但是可以多层继承
- 类与接口
- 实现关系,
- 可以单实现,也可以多实现。
- 还可以在继承一个类的同时实现多个接口。
- 实现关系,
- 接口与接口
- 继承关系,可以单继承,也可以多继承
抽象类和接口的区别
- 成员区别
- 抽象类
- 成员变量:变量,常量;
- 构造方法:可以有
- 成员方法:可以是抽象方法,也可以是非抽象方法;
- 接口
- 成员变量:只可以是常量;
- 构造方法:没有
- 成员方法:只能是抽象方法
- 抽象类
- 关系区别
- 类与类 继承,单继承
- 类与接口 实现,单实现,多实现
- 接口与接口 继承,单继承,多继承
- 设计理念区别
- 抽象类 被继承体现的是:”is a”的关系。抽象类中定义的是该继承体系的共性功能
- 接口 被实现体现的是:”like a”的关系。接口中定义的是该继承体系的扩展功能
- 跳高猫练习:
/*
猫狗案例,加入跳高的额外功能
分析:从具体到抽象
猫:
姓名,年龄
吃饭,睡觉
狗:
姓名,年龄
吃饭,睡觉
由于有共性功能,所以,我们抽取出一个父类:
动物:
姓名,年龄
吃饭();
睡觉(){}
猫:继承自动物
狗:继承自动物
跳高的额外功能是一个新的扩展功能,所以我们要定义一个接口
接口:
跳高
部分猫:实现跳高
部分狗:实现跳高
实现;
从抽象到具体
使用:
使用具体类
*/
//定义跳高接口
interface Jumpping {
//跳高功能
public abstract void jump();
}
//定义抽象类
abstract class Animal {
//姓名
private String name;
//年龄
private int age;
public Animal() {}
public Animal(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//吃饭();
public abstract void eat();
//睡觉(){}
public void sleep() {
System.out.println("睡觉觉了");
}
}
//具体猫类
class Cat extends Animal {
public Cat(){}
public Cat(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("猫吃鱼");
}
}
//具体狗类
class Dog extends Animal {
public Dog(){}
public Dog(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("狗吃肉");
}
}
//有跳高功能的猫
class JumpCat extends Cat implements Jumpping {
public JumpCat() {}
public JumpCat(String name,int age) {
super(name,age);
}
public void jump() {
System.out.println("跳高猫");
}
}
//有跳高功能的狗
class JumpDog extends Dog implements Jumpping {
public JumpDog() {}
public JumpDog(String name,int age) {
super(name,age);
}
public void jump() {
System.out.println("跳高狗");
}
}
class InterfaceTest {
public static void main(String[] args) {
//定义跳高猫并测试
JumpCat jc = new JumpCat();
jc.setName("哆啦A梦");
jc.setAge(3);
System.out.println(jc.getName()+"---"+jc.getAge());
jc.eat();
jc.sleep();
jc.jump();
System.out.println("-----------------");
JumpCat jc2 = new JumpCat("加菲猫",2);
System.out.println(jc2.getName()+"---"+jc2.getAge());
jc2.eat();
jc2.sleep();
jc2.jump();
//定义跳高狗并进行测试的事情自己完成。
}
}
-
运行结果