目录
1、多态
1.1 关于java语言中多态语言机制:
1.2 instanceof
1.3 多态语法的作用
2、final关键字
3、常量
4、package
5、import
6、访问控制权限修饰符
1)Animal、Cat、Bird三个类之间的关系:
Cat继承Animal; Bird继承Animal; Cat和Bird之间没有任何继承关系;
2)向上转型(upcasting) 子类型——>父类型(自动转换)
编译通过,运行一定可以
向下转型(downcasting) 父类型——>子类型(强制类型转换)【需要加强制类型转换符】
编译通过,运行不一定通过,存在隐患
3)无论是向上转型还是向下转型,两者必须要有继承关系;
public class helloworld {
public static void main(String[] args) {
Animal a = new Animal();
a.move();
Bird b = new Bird();
b.move();
Animal a2 = new Bird();//1.1.1关于该语句的解读
a2.move();
//a2.eat(); //1.1.2关于该语句的解读
Bird c2 = (Bird)a2;
c2.eat();
Animal a3 = new Cat();
Bird c3 = (Bird)a3;//1.1.3关于该语句的解读
}
}
class Animal {
public void move() {
System.out.println("动物会跑");
}
}
class Bird extends Animal {
//重写父类中继承的方法
public void move() {
System.out.println("鸟会跑");
}
//这个方法不是从父类中继承过来的,是子类中特有的行为
public void eat() {
System.out.println("鸟吃虫");
}
}
1.1.1 关于Animal a2 = new Bird();
1)java程序分为编译阶段和运行阶段,编译不通过,是根本无法运行的
2)编译阶段,编译器检查a2这个引用的数据类型为Animal,由于Animal.class字节码文件当中有move()方法,所以编译通过了。这个过程我们称为静态绑定,编译阶段绑定,只有静态绑定成功之后才有后续的运行;
3)程序运行阶段,JVM堆内存当中真实创建的对象是Bird对象,那么以下程序在运行阶段一定会调用Bird对象的move方法,此时发生程序的动态绑定,运行阶段绑定;
4)无论是Bird类有没有重写move方法,运行阶段一定调用的是Bird对象的move方法,因为底层真实的对象就是Bird对象;
5)父类型引用指向子类型对象这种机制导致程序存在编译阶段绑定和运行阶段绑定的两种不同形态这种机制可以成为一种多态语法机制;
1.1.2 关于a2.eat();
1)不能调用的原因: 因为编译阶段编译器检查到a2的类型是Animal类型,从Animal.class字节码文件当中查找eat()方法,最终没有找到该方法,导致静态绑定失败,没有绑定成功,也就是编译失败,别谈运行了;
2)如何调用a2.eat?
a2是无法直接调用的,因为a2的类型的Animal,Animal中没有eat()方法,想要调用,必须将a2强制转换成Bird类型,a2的类型是animal(父类),转换成BIrd类型(子类),需要向下转型,被称为向下转型(强制类型转换),需要加强制类型转换符;
向下转型的使用时刻:
当父类中没有子类的特有的方法,必须使用向下转型
1.1.3 关于Bird c3 = (Bird)a3;
1)编译是没有问题的,因为编译器检查到a3的数据类型是Animal,Animal和Bird之间存在继承关系,并且Animal是父类型,Bird是子类型,父类型转换成子类型叫做向下转型,语法合格;
2)程序虽然通过了,但是程序在运行阶段会出现异常,因为JVM堆内存当中真实存在的对象是Cat类型,Cat类型无法转换成Bird对象,两种对象之间不存在继承关系,此时出现了著名的异常java.lang.classCatexception,类型转换异常,这种异常总是在"向下转型"的时候发生;
使用instanceof可以避免向下转型出现的java.lang.classCatexception
1)语法格式:
(引用 instanceof 数据类型名)
2)运算符的执行结果是布尔类型,结果可能是true/false
3)关于运算结果(true/false)
假设:(a instanceof Animal)//a的实例化是动物吗?
true表示 a这个引用指向的对象是Animal类型
false表示 a这个引用指向的对象不是Animal类型
if(a3 instanceof Cat){
Cat c3 = (Cat)a3;
c3.catchMouse();
}eles if(a3 instanceof Bird){
Bird b2 = (Bird)a3;
}
1)降低程序的耦合度,提高程序的扩展力
2)能使用多态尽量使用多态
3)父类型引用指向子类型对象
public class helloworld {
public static void main(String[] args) {
Master zhangsan = new Master();
// Cat tom = new Cat();
// Dog amy = new Dog();
// zhangsan.feed(tom);
// zhangsan.feed(amy);
zhangsan.feed(new Cat());//上面四行代码和这两行实现的功能相同
zhangsan.feed(new Dog());
//new 具体宠物对象的形参传到Pet pet中
//相当于Pet pet = new Dog();
}
}
class Master {
public void feed(Pet pet) {//Pet pet是一个父类型的引用
pet.eat();
}
}
class Cat extends Pet{
public void eat() {
System.out.println("猫吃鱼!");
}
}
class Dog extends Pet{
public void eat() {
System.out.println("狗吃肉!");
}
}
class Pet {
public void eat() {
}
}
表示:最终的,不可变的;
final修饰的类无法被继承;
final修饰的方法无法被覆盖;
final修饰的变量不可二次赋值;
final修饰的实例变量必须手动赋值,不能采用系统默认值;
//方法一:
final int age = 10;
//方法二:
final int age;
public Text(){
this.age = 10;
}//其实本质上是一种方式,都是在构造方法中给实例变量赋值
final修饰的引用
1)一旦指向某个对象后,不能指向别的对象,被指向的对象不能被垃圾回收器回收;
2)虽然指向某个对象后不能指向别的对象,但是所指的对象的内存是可以被修改的
final User user = new User(30);
user = new User(5);//一旦指向某个对象后,不能指向别的对象
user.id = 50;//内存可以被修改
1) final修饰的实例变量一般和static联合使用,称为常量;
2)java规范中要求所有变量的单词全部大写,每个单词之间使用下划线连接;
public static final String GUO_JI = "中国";
public static final double PI = 3.1415926;
1)引入包这个机制为了方便程序的管理,不同的功能的类被分门别类放到不同的软件包中,查找比较方便,管理比较方便,易维护;
2)在java源程序的第一行上编写package语句,package只能编写一个语句;
3)语法结构: package 包名;
4)包名的命名规范: 公司域名倒叙 + 项目 + 模块名 + 功能名; e.g. com.bjpowernode.oa.user.service;(company) org.apache.tomcat.core;(orgnization)
5)包名要求全部小写,包名也是标识符,必须遵循标识符命名规范;
6)一个包将来对应的是一个目录;
7)使用package机制之后,类名是:包名.类名
1)import语句用来导入其他类,同一个包下的类不需要导入
2) import语法格式 import 类名; import 包名.*;
3)import语句需要编写在package语句之下,class语句之上;
java.lang.*不需要手动引入,系统自动引入;
lang:language语言包,是java语言的核心类
String(java.lang.String)
4)eclipse导入类的快捷键Ctr + Shift + o
1)作用:控制元素的访问范围
2)访问控制权限修饰符包括: public 表示公开的, 在任何位置都可以访问; protected 表示受保护的,在同包下、子类可以访问 default(缺省) 不写 在同包下可以访问 private 表示私有的, 在本类中访问;【内部类除外】
3)修饰符范围: private < 缺省 < protected < public