Java学习笔记09
final 关键字引入
- 我们不想让子类去覆盖掉父类的功能(方法重写会覆盖掉父类的方法),只能让父类使用,这个时候,Java就提供了一个关键字:final
- final:常见可以修饰类,方法,变量
final 关键字的特点
- final可以修饰类,该类不能被继承
- final可以修饰方法,该方法不能被重写
- final可以修饰变量,该变量不能被重新赋值,因为这个变量其实是常量
- 常量
- 字面值常量:"hello",10,true
- 自定义常量:final int x = 10
- 代码示例:
//final class Fu//无法从最终Fu进行继承
class Fu {
/*public final void show() {
System.out.println("lhk");
}
*/
public int num = 10;
public final int num2 = 20;
public void show() {
}
}
class Zi extends Fu {
//Zi中的show()无法覆盖Fu中的show()
public void show() {
num = 100;
//num2 = 200;
System.out.println(num);
System.out.println(num2);
}
}
public class finalDemo {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
final 关键字修饰局部变量
- 修饰基本类型:基本类型的值不能发生改变
- 修饰引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值(即类中的变量值)是可以改变的
- 代码示例:
class Student {
int age = 10;
}
public 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);
//final 修饰ss的地址值
//重新分配内存空间给ss,这是不允许的
//ss = new Student();
}
}
final 修饰变量的初始化时机
- 被final 修饰的变量只能赋值一次
- 在构造方法完毕前(非静态的常量)
多态的概述和成员访问特点
- 某一个对象,在不同时刻表现出来的不同状态
- 多态的前提
- 要有继承关系或者实现关系
- 要有方法重写
- 要有父类或者父类接口引用指向子类对象
父 f = new 子();
- 多态的分类
- 具体类多态
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();
- 多态中的成员访问特点
- 成员变量
编译看左边,运行看左边 - 构造方法
创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化 - 成员方法(方法存在覆盖)
编译看左边,运行看右边 - 静态方法
编译看左边,运行看左边
(静态和类相关,算不上重写,所以,访问还是左边的) - 代码示例:
class Fu2 {
public int num = 100;
public void show() {
System.out.println("show Fu2");
}
public static void function() {
System.out.println("function Fu2");
}
}
class Zi2 extends Fu2 {
public int num = 1000;
public int num2 = 100;
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");
}
}
public class DuotaiDemo {
public static void main(String[] args) {
Fu2 fu = new Zi2();
System.out.println(fu.num);
//System.out.println(fu.num2);
fu.show();
//fu.method();
fu.function();
}
}
多态的好处
- 提高了代码的维护性(继承保证)
- 提高了代码的扩展性(由多态保证)
- 代码示例:
class Animal {
public void eat() {
System.out.println("eat");
}
public void sleep() {
System.out.println("sleep");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("eat bone");
}
public void sleep() {
System.out.println("Dog sleep");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("eat fish");
}
public void sleep() {
System.out.println("Cat sleep");
}
}
class Pig extends Animal {
public void eat() {
System.out.println("eat fruit");
}
public void sleep() {
System.out.println("Pig sleep");
}
}
//针对动物类操作的工具书
class AnimalTool {
//让使用者无法创建对象
/*
private AnimalTool() {
}
//调用猫的功能
public static void useCat(Cat cat) {
cat.eat();
cat.sleep();
}
//调用狗的功能
public static void useDog(Dog dog) {
dog.eat();
dog.sleep();
}
//调用猪的功能
public static void usePig(Pig pig) {
pig.eat();
pig.sleep();
}
*/
public static void useAnimal(Animal a) {
a.eat();
a.sleep();
}
}
public class DuotaiDemo2 {
public static void main(String[] args) {
//喜欢猫
Cat cat = new Cat();
cat.eat();
cat.sleep();
//超喜欢猫
Cat cat2 = new Cat();
cat2.eat();
cat2.sleep();
System.out.println("------");
//改进版本
//useCat(cat);
//useCat(cat2);
//AnimalTool.useCat(cat);
//AnimalTool.useCat(cat2);
AnimalTool.useAnimal(cat);
AnimalTool.useAnimal(cat2);
System.out.println("------");
//我喜欢狗
Dog dog = new Dog();
Dog dog2 = new Dog();
//AnimalTool.useDog(dog);
//AnimalTool.useDog(dog2);
AnimalTool.useAnimal(dog);
AnimalTool.useAnimal(dog2);
System.out.println("------");
//我喜欢猪
Pig pig = new Pig();
Pig pig2 = new Pig();
//AnimalTool.usePig(pig);
//AnimalTool.usePig(pig2);
AnimalTool.useAnimal(pig);
AnimalTool.useAnimal(pig2);
System.out.println("------");
//我喜欢的动物还有很多
//但我们必须写一个方法去代替重复构造动物功能的过程
}
}
多态的弊端和解决方法
- 父不能使用子类的特有功能
- 我们要解决这个问题:多态中向上转型和向下转型
- 向上转型:Fu f = new Zi();
- 向下转型:Zi z = (Zi)f;//要求该f必须是能够转换为Zi的
- 代码示例:
class Fu3 {
public void show() {
System.out.println("show Fu3");
}
}
class Zi3 extends Fu3 {
public void show() {
System.out.println("show Zi3");
}
public void method() {
System.out.println("method Zi3");
}
}
public class DuotaiDemo3 {
public static void main(String[] args) {
Fu3 fu3 = new Zi3();
fu3.show();
//fu.method();
//我们能够把子的对象赋值给父亲,那能否把父的引用赋值给子的引用呢?
Zi3 zi3 = (Zi3)fu3;//向下转型
zi3.show();
zi3.method();
}
}
多态中的内存图解
- 多态继承中的内存图解
- [图片上传失败...(image-39fa80-1510752835050)]
- 多态中的对象变化内存图解
- [图片上传失败...(image-340db8-1510752835050)]
多态基本案例
- 代码示例:
class Animal2 {
public void eat() {
System.out.println("eat");
}
}
class Dog2 extends Animal2 {
public void eat() {
System.out.println("bone");
}
public void lookDoor() {
System.out.println("lookDoor");
}
}
class Cat2 extends Animal2 {
public void eat() {
System.out.println("fish");
}
public void playGame() {
System.out.println("sweater");
}
}
public class DuotaiTest {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Animal2 animal = new Dog2();
animal.eat();
System.out.println("-------");
//还原成狗
Dog2 d = (Dog2)animal;
d.eat();
d.lookDoor();
System.out.println("-------");
//变成猫
animal = new Cat2();
animal.eat();
System.out.println("-------");
//还原成猫
Cat2 cat = (Cat2)animal;
cat.eat();
cat.playGame();
System.out.println("-------");
}
}
抽象类的概述
- 在Java 中,我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类
抽象类的特点
- 格式:
- 抽象类和抽象方法必须用abstract 关键字修饰
- 抽象类中不一定有抽象方法,但是有抽象方法的类
- 抽象类不能实例化(抽象类有构造方法,但是不能实例化,构造方法用于子类访问父类数据的初始化)
- 抽象的子类
a. 如果不想重写抽象方法,该子类是一个抽象类
b. 重写所有的抽象方法,这时候子类是一个具体的类
- 抽象类的实例化其实是靠具体的子类实现的,是多态的方式
- 代码示例:
abstract class Animal4 {
//抽象方法
//public abstract void eat() {}//空方法体,报错
public abstract void eat();//没有方法体
}
//子类是抽象类
abstract class Dog4 extends Animal4 {}
//子类是具体类,重写抽象方法
class Cat4 extends Animal4 {
public void eat() {
System.out.println("eat fish");
}
}
public class ChouxiangDemo {
public static void main(String[] args) {
// TODO 自动生成的方法存根
//通过多态的方法
Animal4 animal4 = new Cat4();
animal4.eat();
}
}
抽象类的成员特点
- 成员变量:既可以是变量,也可以是常量
- 构造方法:有,用于子类访问父类数据的初始化
- 成员方法:既可以是抽象的,也可以是非抽象的
- 抽象类的成员方法特征
- 抽象方法:强制要求子类做的事情
- 非抽象方法,子类继承的事情,提高代码的复用性
- 代码示例:
abstract class Animal5 {
public int num = 10;
public Animal5() {}
public Animal5(String name,int age) {}
public abstract void show();
public void method() {
System.out.println("show method");
}
}
class Dog5 extends Animal5 {
public void show() {
System.out.println("show Dog5");
}
}
public class AbstractDemo {
public static void main(String[] args) {
Animal5 animal5 = new Dog5();
System.out.println(animal5.num);
System.out.println("------");
animal5.show();
animal5.method();
}
}
示例代码
//定义员工类
abstract class Employee {
private String name;
private String id;
private int salary;
public Employee() {
}
public Employee(String name,String id,int salary) {
this.name = name;
this.id = id;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getid() {
return id;
}
public void setid(String id) {
this.id = id;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
//工作
public abstract void work();
}
//员工
class programmer extends Employee {
public programmer() {
}
public programmer(String name,String id,int salary) {
super(name, id, salary);
}
public void work() {
System.out.println("code");
}
}
//经理
class manager extends Employee {
private int money;
public manager() {
}
public manager(String name,String id,int salary,int money) {
super(name, id, salary);
this.money = money;
}
public void work() {
System.out.println("communicate");
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
public class AbstractTestDemo3 {
public static void main(String[] args) {
//测试普通员工
Employee employee = new programmer();
employee.setName("lhk");
employee.setid("hk");
employee.setSalary(1000000000);
System.out.println(employee.getName() + "---" + employee.getid() + "---" + employee.getSalary());
System.out.println("-------");
employee = new programmer("lhk","nihao",10000);
System.out.println(employee.getName() + "---" + employee.getid() + "---" + employee.getSalary());
System.out.println("-------");
/*
employee = new manager();
employee.setName("lhk");
employee.setid("hk");
employee.setSalary(2000000000);
employee.setmoney(3151345);
*/
//由于子类特有的内容,所以我们用子类来测试
manager manager = new manager();
manager.setName("lhk");
manager.setid("hk");
manager.setSalary(2000000000);
manager.setMoney(3151345);
System.out.println(manager.getName() + "---" + manager.getid() + "---" + manager.getSalary() + "---" + manager.getMoney());
manager.work();
System.out.println("-------");
//通过构造方法赋值
manager = new manager("lhk","hk",66666,352354);
System.out.println(manager.getName() + "---" + manager.getid() + "---" + manager.getSalary() + "---" + manager.getMoney());
manager.work();
}
}
抽象类中的小问题
- 一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
- 可以
- 不让外界创建对象
- abstract 不能和哪些关键字共存
- private 冲突
建立抽象方法的目的是让子类去重写这个方法,而一旦加了private,子类就不能进行重写了,无意义
- final 冲突
同理,子类不能进行方法重写
- static 无意义
- 代码示例:
abstract class Fu6 {
//public abstract void show();
//非法的修饰符组合:abstract和private
//private abstract void show();
//非法的修饰符组合
//final abstract void show();
//show方法没有方法体,访问一个没有方法体的方法,无意义
//static abstract void show();
public static void method() {
System.out.println("method");
}
}
class Z6 extends Fu6 {
public void show() {
}
}
public class XiaoWenTiDemo {
public static void main(String[] args) {
Fu6.method();
}
}
接口的成员特点
- 成员变量:只能是常量,并且是静态的
默认修饰符:public static final
建议手动给出 - 构造方法:接口没有构造方法
- 成员方法:只能是抽象方法
默认修饰符:public abstract
建议手动给出 - 所有的类都默认继承自一个类:Object
类Object 是类层次结构的根类,每个类都使用Object 作为超类 - 代码示例:
interface Inter {
public int num = 10;
public final int num2 = 20;
//完整版中的接口变量
public static final int num3 = 30;
//public Inter() {}
//接口方法不能带有主体
//public void show() {}
//abstract void show();默认是public
public void show();//默认是abstract
}
//接口名+Impl这种格式是接口的实现类格式
//class InterImpl extends Object implements Inter {}
class InterImpl implements Inter {
public InterImpl() {
super();
}
public void show() {
}
}
public class InterfaceDemo {
public static void main(String[] args) {
Inter inter = new InterImpl();
System.out.println(inter.num);
System.out.println(inter.num2);
//inter.num = 199;
//无法为num或者num2分配值,因为接口中默认num已为常量
//和final效果一样
System.out.println("------");
System.out.println(Inter.num);
System.out.println(Inter.num2);
}
}
类与类,类与接口,接口与接口的关系
- 类与类
- 继承关系:只能单继承,但是可以多层继承
- 类与接口
- 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
- 接口与接口
- 继承关系,可以单继承,也可以多继承
- 代码示例;
package exp2.demo;
/*
* 类与类:继承关系:只能单继承,但是可以多层继承
* 类与接口:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
* 接口与接口:继承关系,可以单继承,也可以多继承
*/
interface Father {
public void show();
}
interface Mother {
public abstract void show2();
}
interface Sister extends Father,Mother {
}
//class Son implement Father,Mother //多实现
//还可以在继承一个类的同时实现多个接口
class Son extends Object implements Father,Mother{
public void show() {
System.out.println("show son");
}
public void show2() {
System.out.println("show2 son");
}
}
public class AbstractDemo {
public static void main(String[] args) {
Father father = new Son();
father.show();
//father.show2();
Mother mother = new Son();
mother.show2();
//mother.show();
}
}
抽象类和接口的区别
- 成员区别
- 抽象类:
成员方法:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象 - 接口:
成员变量:只可以常量
成员方法:只可以抽象
- 关系区别
- 类与类:继承,单继承
- 类与接口:实现,单继承,多实现
- 接口与接口:继承,单继承,多继承
- 设计理念区别
- 抽象类:被继承体现的是:“is a”的关系,抽象类中定义的是该继承体现的共性功能
- 接口:被实现体现的是:“like a”的关系,接口中定义的是该继承体系的扩展功能
跳高猫代码示例
package exp2.demo;
//定义跳高接口
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("sleep");
}
}
class Dog extends Animal {
public Dog() {}
public Dog(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("eat bone");
}
}
class Cat extends Animal {
public Cat() {}
public Cat(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("eat fish");
}
}
//跳高猫
class JumpCat extends Cat implements Jumpping {
public JumpCat() {}
public JumpCat(String name,int age) {
super(name,age);
}
public void jump() {
System.out.println("jump cat");
}
}
public class TestDemo {
public static void main(String[] args) {
//定义跳高猫
JumpCat jumpCat = new JumpCat();
jumpCat.setName("nihao");
jumpCat.setAge(20);
System.out.println(jumpCat.getName() + jumpCat.getAge());
jumpCat.eat();
jumpCat.sleep();
jumpCat.jump();
System.out.println("------");
}
}
网友评论