day02【final、静态、多态】
昨日反馈和回顾
能够写出类的继承格式
public class 子类 extends 父类{
}
能够说出Java继承的特点
a.单继承(一个子类只能有一个父类,一个父类可以有多个子类)
b.多层继承(一个子类可以有一个父类,该父类也可以有自己的父类)
能够说出子类调用父类的成员特点
如果子父类中有同名的成员变量/成员方法,根据Java就近原则,优先调用子类自己成员
如果子父类中不同名的成员变量/成员方法,根据变量或者方法名字调用,不存在歧义
构造方法,a.父类的构造子类无法继承 b.在子类的任何构造第一行,默认调用父类的无参构造,super()
够说出方法重写的概念
方法重载(overload): 在同一个类中,方法名一样的,参数列表不一样
方法重写(override): 在继承关系中,子类中有一个和父类除了方法体(权限修饰符),其他一模一样的方法
能够说出this可以解决的问题
在本类中使用:
this.xxx 访问本类的成员变量
this.xxx() 调用本类的成员方法
this(...) 调用本类的其他构造
能够说出super可以解决的问题
在子类中使用:
super.xxx 访问父类继承的成员变量
super.xxx() 调用父类继承的成员方法
super(...) 调用父类构造方法
描述抽象方法的概念
抽象方法: 只有方法的声明,没有方法的实现(加上关键字abstract)
抽象类: 含有抽象方法的类一定是一个抽象类
如果是一个抽象类,其中不一定含有抽象方法
写出抽象类的格式
public abstract class 抽象类名{
抽象方法
正常方法
}
写出抽象方法的格式
public abstract void 抽象方法名();
能够说出父类抽象方法的存在意义
抽象类的意义: 给其他子类继承的,为子类提供模板(模板设计模式)
抽象方法的意义: 要求子类必须重写(如果不重写,子类还是一个抽象类)
今日内容介绍
a.关键字final
b.关键字static
c.引用类型_接口(重点)
第一章 final关键字
1.1 final关键字
final什么意思: 最终的,不可变的
final在Java中是一个修饰符:
修饰类,修饰方法,修饰局部变量,修饰成员变量,修饰引用类型变量
1.2 final的作用介绍
-
final修饰类
被final修饰的类,我们称为太监类,不能被继承 /** * 父类 */ public final class Fu { } /** * 子类报错了,因为父类是final类,不能被继承 */ public class Zi extends Fu { } 注意: final修饰的类没有子类,并不是说它不能继承别的类
-
final修饰方法
被final修饰的方法,不能被重写!! /** * 父类 */ public class Fu { //final修饰方法 public final void show() { System.out.println("show..."); } } /** * 子类 */ public class Zi extends Fu{ //重写报错!!! //因为父类的show方法是final修饰的,子类不允许重写 @Override public void show() { System.out.println("重写后的show..."); } }
-
final修饰局部变量
被final修饰的局部变量,表示该变量只能赋值一次 public class TestDemo { public static void main(String[] args) { //定义一个局部变量 //给它加上final修饰 final int num = 10; //报错了!! 因为final修饰的局部变量,只能赋值一次 num = 20; num = 30; num = 40; System.out.println(num); } } 注意: final int num = 10; 这句代码也可以写出以下两句 final int num; num = 10; 这也是OK的!!
思考:如下两种写法,哪种可以通过编译?
写法1: 报错!! final int c = 0; //只能赋值一次 for (int i = 0; i < 10; i++) { c = i; // 第二次赋值了,报错!!! System.out.println(c); } 写法2: 编译通过! for (int i = 0; i < 10; i++) { final int c = i; //c也是final修饰的 //因为c是在循环体中定义的,每次循环都是新的一个c System.out.println(c); }
-
final修饰引用类型的变量
final修饰引用类型的变量,表示该引用类型变量中保存的地址值不能改变量 public class Dog { int age = 10; String name = "旺财"; } public class TestDog { public static void main(String[] args) { //1.创建一个引用类型的变量 // 给引用类型的变量也叫上final final Dog d = new Dog(); // d中是对象的地址 0x111 //报错的!!!!因为final修饰d,表示d中地址值不能改变 d = new Dog(); //将d中的对象地址 改为 0x222 } } 注意: final修饰d只表示d中地址不能改变,并不代表d中的成员变量值不能改变, 以下写法是正确的: d.age = 20; d.name = "来福";
-
final修饰成员变量
被final修饰的成员变量,只能赋值一次,必须赋值 但是赋值可以有两种选择: a.定义该成员变量的时候赋值 public class Student { //使用final修饰成员变量 final int age = 10; } b.或者在构造方法中给该成员变量赋值 public class Student { //使用final修饰成员变量 final int age; //在构造方法中赋值 public Student(){ this.age = 20; } } 总之,final修饰的成员变量,必须在创建对象之前有值
第二章 static关键字
2.1 概述
static什么意思: 静态关键字
static也是一个修饰符,用于修饰类中成员变量/成员方法,被static修饰的成员我们称之为静态成员/类成员
"被static修饰的成员,不属于任何一个对象,属于整个类,被所有对象共享"
2.2 定义和使用格式
-
类变量
类变量:就是使用static修饰的成员变量,我们称为类变量/静态变量 "被static修饰的成员变量,不属于任何一个对象,属于整个类,被所有对象共享" /** * 学生类 */ public class Student { int age; String name; //静态变量,类变量,在内存的方法区中的静态区,只有一份(所有对象共享它) static String school = "黑马程序员"; public void show(){ System.out.println("姓名:"+name+",年龄:"+age+",学校:"+school); } } public class TestStudent { public static void main(String[] args) { //1.第一个学生 Student s1 = new Student(); s1.name = "孙嘉华"; s1.age = 18; s1.show(); System.out.println("============"); //2.第二个学生 Student s2 = new Student(); s2.name = "赵广顺"; s2.age = 35; s2.show(); System.out.println("============="); //孙嘉华同学去了"传智专修学院" //修改了静态区中的共享变量,所有对象访问时,都能看到修改后的结果 s1.school = "传智专修学院"; System.out.println("============="); s1.show(); s2.show(); } }
-
静态方法
静态方法也叫类方法,由static修饰的方法 特点: 正常的方法必须通过对象才能调用,静态方法不需要通过对象,通过类名就可以直接调用 /** * 计算器类 */ public class Calculator { //计算两个数的和 //这就是静态方法/类方法 public static int getSum(int a, int b) { return a + b; } } public class TestCalculator { public static void main(String[] args) { //1.创建对象 // Calculator cc = new Calculator(); // int sum = cc.getSum(111, 999); // System.out.println("求和为:"+sum); //2.静态方法,直接通过类名调用即可 int sum = Calculator.getSum(111, 999); System.out.println("求和为:"+sum); } }
2.3 静态和非静态之间的相互调用
静态成员变量
静态成员方法
与类是同级,只要类加载到内存,静态的成员变量/成员方法就存在(对象不一定存在)
非静态成员变量
非静态成员方法
必须创建对象之后才能访问/调用
生命周期看:
静态出现的比非静态要早!!!!
结论:
a.静态与静态之间,非静态与非静态之间是可以相互访问的
b.非静态可以访问静态,但是静态不能访问非静态
静态的: 秦始皇(出现早)
非静态: 我们(出现晚)
2.4 建议调用格式
静态的成员变量
对象名.静态的成员变量 【可以访问的,但是我们不建议】
类名.静态的成员变量 【建议访问的方式】
静态的成员方法
对象名.静态的成员方法() 【可以访问的,但是我们不建议】
类名.静态的成员方法() 【建议访问的方式】
总结: 静态成员虽然可以通过对象名去访问/调用,但是我们更建议直接使用类名去访问/调用
第三章 接口【重要】
3.1 概述
什么是接口:
也是一种引用类型,接口是方法的集合(接口中主要写方法)
3.2 定义格式
定义类: class
定义接口: interface
定义枚举: enum 【以后讲解】
定义注解: @interface 【以后讲解】
格式:
public interface 接口名{
//抽象方法【JDK7】
//默认方法和静态方法【JDK8】
//私有方法和私有静态方法【JDK9了解】
}
/**
* 定义接口的格式
*/
public interface MyInterface {
//抽象方法【主要】,只有接口中抽象方法 public abstract 关键字可以省略(省略不代表没有,编译器会自动添加)
public abstract void abs1();
public abstract void abs2();
//默认方法
//使用一个关键字修饰 default
public default void m1(){
System.out.println("接口中的默认方法1");
}
public default void m2(){
System.out.println("接口中的默认方法2");
}
//静态方法
//使用一个关键字 static
public static void s1(){
System.out.println("接口中的静态方法1");
}
public static void s2(){
System.out.println("接口中的静态方法2");
}
}
3.3 接口的使用
a.和抽象类类似,接口也是不能创建的对象的
b.接口也是作为父接口使用的,用于被其他类"实现"的
c.继承使用extends关键字,实现使用"implements"关键字
使用方式:
public class 实现类 implements 接口名{
//a.必须重写接口中所有的抽象方法
//b.选择性重写接口中的默认方法,但是重写后不能有default
//c.静态方法没有重写的说法,因为它是通过所在类/接口的名字直接调用的
}
/**
* 实现类
*/
public class MyClass implements MyInterface {
//a.实现类 必须 重写接口中的所有抽象方法
@Override
public void abs1() {
System.out.println("重写后的abs1...");
}
@Override
public void abs2() {
System.out.println("重写后的abs2...");
}
//b.实现类 可以 选择性重写默认方法,但是重写后不能加default
@Override
public void m1() {
System.out.println("重写后的m1方法..");
}
//c.静态方法通过类名/接口名 直接调用的,没有重写这种说法
public static void s1(){
System.out.println("实现类中的静态方法1");
}
}
测试类
public class TestDemo {
public static void main(String[] args) {
//1.创建实现类对象
MyClass mc = new MyClass();
//2.抽象方法
mc.abs1();
mc.abs2();
//3.默认方法
mc.m1(); //调用实现类的重写方法
mc.m2(); //调用接口中的默认方法
//4.静态方法
MyInterface.s1(); // 接口的s1
MyClass.s1(); // 实现类的s1
}
}
3.4 接口的多实现
格式:
public class 实现类 implements 接口1,接口2,..{
//a.实现类需要重写所有接口中的所有抽象方法
//如果有抽象方法是一样的,那么实现类只需要重写一次
//b.实现类可以选择性重写所有接口中的默认方法
//如果接口中有一样的默认方法,实现类必须重写一次
//c.静态方法没有重写的概念,就算多个接口中有一样的静态方法
//也不冲突,通过各位所在的接口名调用,没有歧义
}
/**
* 实现类:多实现
*/
public class MyClass implements MyInter1,MyInter2{
//1.抽象方法
//实现类必须重写所有接口中的所有抽象方法
//如果有抽象方法是一样的,那么实现类只需要重写一次
@Override
public void abs1() {
System.out.println("实现类重写后的抽象方法1..");
}
@Override
public void abs2() {
System.out.println("实现类重写后的抽象方法2...");
}
//abs方法
@Override
public void abs() {
System.out.println("实现类重写后的抽象方法s");
}
//2.默认方法
//实现类可以选择性重写所有接口中的默认方法
//如果接口中有一样的默认方法,实现类必须重写一次
@Override
public void show() {
System.out.println("实现类重写后的默认方法show...");
}
//3.静态方法
//静态方法没有重写的概念,就算多个接口中有一样的静态方法
//也不冲突,通过各位所在的接口名调用,没有歧义
//通过MyInter1.s()和通过MyInter2.s()
public static void s(){
System.out.println("实现类自己的s方法");
}
}
public class TestDemo {
public static void main(String[] args) {
//创建实现类对象
MyClass mc = new MyClass();
//1.抽象方法
mc.abs1();
mc.abs2();
mc.abs();
//2.默认方法
mc.show1(); //调用接口1的默认方法show1
mc.show2(); //调用接口2的默认方法show2
mc.show(); //调用实现类重写后的show
//3.静态方法
MyInter1.s();
MyInter2.s();
MyClass.s();
}
}
3.5 实现和继承的优先级问题
一个类 可以在继承一个父类的同时实现多个接口(继承和实现可以同时存在)
格式:
public class 子类/实现类 extends 父类 implements 接口,...{
}
继承的优先级 高于 实现,所以必须先extends后implements
public interface MyInter {
//默认方法
public default void show(){
System.out.println("接口的默认方法");
}
}
public class Fu {
//正常方法
public void show(){
System.out.println("父类的show方法");
}
}
public class Zi extends Fu implements MyInter{
//如果父类中的正常方法和接口中的默认方法一样了
//a.那么子类需要不需要对同名的show方法进行重写呢??
//子类可以不重写该方法,调用优先调用父类中的show
//b.那么子类能不能重写show方法呢???
//可以重写,重写后,优先调用子类重写后的方法
@Override
public void show() {
System.out.println("子类重写后的show...");
}
}
public class TestDemo {
public static void main(String[] args) {
//1.创建子类对象
Zi zz = new Zi();
zz.show();
}
}
3.6 接口的多继承【了解】
类和类之间: 单继承
类和接口之间: 多实现
接口和接口之间: 多继承
格式:
public interface MyInter extends Inter1,Inter2{
MyInter接口包含Inter1和Inter2接口所有东西
}
接口多继承我们只做了解即可,我们在开会中很少写这种代码
public class MyClass implements MyInter{
}
和
public class MyClass implements Inter1,Inter2{
}
效果是一样
3.7 接口中其他成员特点
a.接口中,无法定义成员变量,但是可以定义常量(字面值常量,由public static fina修饰的常量)
其值不可以改变,默认使用public static final修饰(可省略,但是编译器会自动添加)
【public static final】 数据类型 常量名 = 值; 【常量名一般纯大写,多个单词之间使用_分隔】
b.接口中,没有构造方法,不能创建对象。
c.接口中,没有静态代码块【明后天讲解】
3.8 抽象类和接口的练习
案例介绍:
代码实现
/**
* 狗类,所有狗的共性内容
*/
public class Dog {
int age;
String name;
public void bark(){
System.out.println("小狗汪汪~~~");
}
public void run(){
System.out.println("小狗旺旺~~~");
}
}
/**
* 缉毒接口,其中包含缉毒抽象方法
*/
public interface JiDu {
//缉毒抽象方法
public abstract void jiDu();
}
/**
* 超级狗(缉毒狗)
*/
public class SuperDog extends Dog implements JiDu{
//必须重写接口的缉毒方法
@Override
public void jiDu() {
System.out.println("旺旺,站住,别跑,否则老子开抢了...");
}
}
public class TestDemo {
public static void main(String[] args) {
//1.创建一个缉毒狗
SuperDog superDog = new SuperDog();
//2.调用方法
superDog.bark();
superDog.run();
superDog.jiDu();
}
}
总结
描述final
修饰类: 该类不能被继承
修饰方法: 该方法不能被重写
修饰变量: 该变量只能赋值一次
局部变量: 可以在定义时赋值,可以先定义后赋值
成员变量: 可以在定义时赋值,可以在构造方法中赋值
引用类型变量: 表示该引用类型变量的地址值不能改变,但是地址内成员变量的值是可以改变
能够掌握static关键字修饰的变量调用方式
类名.成员变量名【建议的使用方式】
能够掌握static关键字修饰的方法调用方式
类名。成员方法名() 【建议的使用方式】
能够写出接口的定义格式
public interface 接口名{
//抽象方法【我们最最最常写】
//默认方法
//静态方法
}
能够写出接口的实现格式
public class 实现类 implements 接口名,...{
//a.重写所有抽象方法,如果有相同只需要重写一次
//b.选择性重写默认方法,如果相同必须重写一次
//c.静态方法没有重写的概念
}
能够说出接口中的其他成员特点
a.没有成员变量,只有常量
[public static final] 数据类型 常量名 = 值;
b.没有构造方法,也不能创建对象
c.也没有静态代码块[明后天搞定!]