super关键字
super表示调用父类方法
-
调用父类构造方法 super(参数列表)
-
当在子类中调用父类无参构造时,super(可写可不写)
-
当子类调用父类有参构造时,super(参数列表)必须要写,告知编译器调用的是哪个父类有参构造 ******
-
super与this在构造方法中不能同时存在,即子类不存在构造方法的互相调用
super调用父类普通方法
-
super.方法名(参数列表) 明确表示调用父类中被覆写的方法
使用super调用父类的同名方法
class Person{
public void print(){
System.out.println("1.I am father");
}
}
class Student extends Person{
public void print(){
//使用super.方法() 调用父类中被覆写的方法
super.print();
System.out.println("2.I am child");
}
}
//主类
public class Test{
//主函数
public static void main(String[] args){
new Student().print();
}
}
//打印结果如下
//1.I am father
//2.I am child
super表示调用父类属性(了解)
//使用super调用父类属性
class Person{
public String info ="爸爸!";
}
class Student extends Person{
public String info ="儿子!";
public void print(){
//使用super.属性调用父类中的属性
System.out.println(super.info);
System.out.println(this.info);
}
}
//主类
public class Test{
//主函数
public static void main(String[] args){
new Student().print();
}
}
//打印结果如下
//爸爸
//儿子
this与super区别 ***重要***
区别 | this | super | |
1 | 概念 | 访问本类中的属性和方法 | 访问父类中的属性和方法 |
2 | 查找范围 | 先查找本类,若本类没有就调用父类 | 不查找本类,直接调用父类定 |
3 | 特殊 | 表示当前对象 | 无 |
this与super使用举例
class Person {
public static void prt(String s) {
System.out.println(s);
}
Person() {
prt("A Person.");
}
Person(String name) {
prt("A person name is:" + name);
}
}
class Chinese extends Person {
Chinese() {
super(); // 调用父类构造函数(1)
prt("A chinese.");// (4)
}
Chinese(String name) {
super(name);// 调用父类具有相同形参的构造函数(2)
prt("his name is:" + name);
}
Chinese(String name, int age) {
this(name);// 调用当前具有相同形参的构造函数(3)
prt("his age is:" + age);
}
}
public class Test{
public static void main(String[] args) {
Chinese cn = new Chinese();
cn = new Chinese("Dyson");
cn = new Chinese("Dyson", 22);
}
}
// 打印结果如下
// A Person.
// A chinese.
// A person name is:Dyson
// his name is:Dyson
// A person name is:Dyson
// his name is:Dyson
// his age is:20
final关键字
-
final修饰类:当一个类用final定义后,表示该类不允许被继承。同时,该类中的所有方法都会被隐式加上final关键字(不包括成员变量)
-
final修饰方法:当一个方法被final关键字定义后,表示该方法不允许被覆写。final方法常用于模板方法---保护性
-
final修饰属性:当属性被final修饰后,表示该属性值不可变。并且该属性必须要在声明时初始化,构造方法初始化,构造块初始化,否则就会编译出错
a.final修饰基本数据类型变量(99%)
在类中的常量一般使用final+static,描述全局变量
全局常量命名规范:多个单词全大写,且单词间以_分隔
eg. public static final int MY_AGE = 10 ;
b.final修饰引用数据类型变量(地址不可变)
String类以及8大数据类型包装类(Integer)都是final类---保护性
数据类型转化
在Java中当使用 +、-、*、/、%、运算操作时,遵循如下规则:
- 只要两个操作数中有一个是double类型的,另一个将会被转换成double类型,并且结果也是double类型,如果两个操作数中有一个是float类型的,另一个将会被转换为float类型,并且结果也是float类型,如果两个操作数中有一个是long类型的,另一个将会被转换成long类型,并且结果也是long类型,否则(操作数为:byte、short、int 、char),两个数都会被转换成int类型,并且结果也是int类型。但是final修饰的域类型不会发生变化.
例题:请选出下面出错的语句 ***重要***
byte b1=1,b2=2,b3,b6,b8;
final byte b4=4,b5=6,b7=9;
public void test() {
b3=(b1+b2); /*语句1*/ 当执行语句1时,b1和b2都会被转化为int类型,当大类型赋值给小类型时必须要强转
b6=b4+b5; /*语句2*/ 当执行语句2时,由于b4和b5都是被final修饰,所以他们的类型不会发生改变
b8=(b1+b4); /*语句3*/ 理由同语句1
b7=(b2+b5); /*语句4*/ 理由同语句1
System.out.println(b3+b6);
}
答案:只有语句2正确;
多态性
概念总结:
-
对象多态性的核心在于方法的覆写。
-
通过对象的向上转型可以实现接收参数的统一,向下转型可以实现子类扩充方法的调用(一般不操作向下转型,有安全隐患)。
-
两个没有关系的类对象是不能够进行转型的,一定会产生ClassCastException
多态:同一个类实例的相同方法在不同情况下有不同的表现形式
-
向上转型(90%)核心用处参数统一化 ***重要***
父类 父类引用 = new 子类();
Person per =new Student();
不管是否发生了向上转型,核心本质还是在于:你使用的是哪一个子类(new在哪里),而且调用的方法是否被子类所覆写了,和覆写的结果差不多
class Person {
public void print(){
System.out.println("1.我是爸爸!");
}
}
class Student extends Person {
public void print(){
System.out.println("2.我是儿子!");
}
}
public class Test{
public static void main(String[] args) {
//向上转型
Person per=new Student();
per.print();
}
}
//打印结果如下
//2.我是儿子!
-
向下转型(1%)--需要强制类型转换-用于父类引用需要调用子类扩充方法时
子类 子类引用 = (子类) 父类实例;
Student stu = (Student) per;
要发生向下转型,必须先发生向上转型(爹认儿子,亲子鉴定)
在向下转型前先判断是否要要想上转型
(运行时异常 RTTI) ClassCastException(类转型异常) :发生在两个不能强转的类之间
引用 instanceof 类:表示该类引用能否指向该类实例 返回 boolean
per instanceof Student
class Person {
public void print(){
System.out.println("1.我是爸爸!");
}
}
class Student extends Person {
public void print(){
System.out.println("2.我是儿子!");
}
public void fun(){
System.out.print("只有儿子有!");
}
}
public class Test{
public static void main(String[] args) {
//向上转型
Person per=new Student();
per.print();
//per一定是父类的对象,但不一定子类的对象,要先进行向下转型才能表示子类对象
System.out.println(per instanceof Person);
System.out.println(per instanceof Student);
if (per instanceof Student) {
//避免ClassCastException
//强转
Student stu = (Student) per ;
stu.fun();
}
//强转
// Student stu=(Student) per;
//stu是子类引用不论是否转型,都既可以为父类的对象也是子类的对象
// System.out.println(per instanceof Person);
// System.out.println(per instanceof Student);
// stu.fun();
}
}
向上转型最核心用处 -- 参数统一化
class Person {
public void print(){
System.out.println("1.我是人类!");
}
}
class Student extends Person {
public void print(){
System.out.println("2.我是学生!");
}
}
class Worker extends Person {
public void print(){
System.out.println("3.我是工人!");
}
}
public class Test{
public static void main(String[] args) {
//将对象向上转型
whoYouAre(new Student());
whoYouAre(new Worker());
}
public static void whoYouAre(Person per){
per.print();
}
}
// 打印结果如下
// 2.我是学生!
// 3.我是工人!
关于强制类型转换
编译器在编译时只会检查类型之间是否存在继承关系,有则通过;而在运行时就会检查它的真实类型,是则通过,否则抛出ClassCastException异常
比如如说:
oppo op=new oppo();
vivo vi=(vivo)op;
/*
这样就会直接在编译期间报错,应为两个类之间不存在任何继承关系
*/
phone ph=new phone();
oppo op=(oppo)ph;
/*
phone是oppo的父类,当引用类型的真实身份为父类本身时,强制类型转化就会在运行期间出现错误
*/
在继承中,子类可以自动转型为父类,但是父类强制转换为子类时只有当引用类型真正的身份为子类时才会强制转换成功,否则失败
实例方法和静态方法之间的关系 ***重要***
-
静态方法只能访问静态成员,实例方法可以访问静态和实例成员。
-
静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。
-
静态方法在程序初始化后会一直贮存在内存中,不会被垃圾回收器回收,非静态方法只在该类初始化后贮存在内存中,当该类调用完毕后会被垃圾回收器收集释放。
-
静态方法在初始化类时初始化,并分配内存;动态方法只有先创建类的实例对象后,才能调用动态方法
-
在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。