JavaSe学习笔记 day07
一、抽象类
关键字:abstract
abstract可以修饰:方法和类
abstract修饰类(抽象类):
- 抽象类不能被实例化
- 思考 :抽象类有没有构造器?有 - 因为子类对象的实例化过程
- 非抽象子类继承抽象类后必须重写抽象父类中的所有抽象方法
- 如果非抽象子类不想重写抽象父类中的抽象方法,那么该子类也需要变成抽象子类。
- 抽象子类可以重写抽象父类中的抽象方法,如果直接抽象父类重写了间接抽象父类中的抽象方法那么非抽象子类就不需要再重写该抽象方法
- 抽象类中不是必须有抽象方法的。
//继承抽象类
abstract class A{ //包含抽象方法所以必须定义为抽象类
public static final String FLAG = "CHINA";
private String name = "Jerry";
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public abstract void print(); //定义抽象方法。只需要声明,不需要实现。
}
//抽象类必须被子继承才可用抽象类
class B extends A{
//因为子类不是抽象类,所以必须覆写抽象类中的全部抽象方法
public void print(){
System.out.println("FLAG = " + FLAG);
System.out.println("姓名 = " + super.getName());
}
}
public class AbstractDemo02{
public static void main(String args[]){
B b = new B();
b.print();
}
}
abstract修饰方法(抽象方法):
- 抽象方法没有方法体
- 抽象方法所在的类必须为抽象类
- abstract不可以和哪些关键字一起使用?
final,private,static
//调用抽象类中指定参数的构造方法
abstract class Person{
private String name;
private int age;
public Person(String name, int age){
this.setName(name);
this.setAge(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 String getInfo(); //取得信息,抽象方法
}
class Student extends Person{
private String school;
public Student(String name, int age, String school){
super(name, age);
this.setSchool(school);
}
public String getSchool(){
return school;
}
public void setSchool(String school){
this.school = school;
}
public String getInfo(){ //覆写抽象类中的抽象方法
return "姓名:" + super.getName() +
";年龄:" + super.getAge() +
";学校:" + this.getSchool();
}
}
public class AbstractDemo03{
public static void main(String args[]){
Student stu = new Student("张三", 30, "清华大学");
System.out.println(stu.getInfo());
}
}
总结:抽象类就是比普通类多定义了一个抽象方法,除了不能直接进行对象的实例化操作之外并没有任何的不同。
二、接口
接口(Interface):接口的地位等同于class, 接口中的所有方法都是抽象方法。在声明接口中的方法时,可以使用 abstract 关键字,也可以不用。通常情况会省略 abstract 关键字。
1.概念:可以将接口看作是特殊的抽象类(抽象类中可以有具体方法,也可以有抽象方法,而接口中只能有抽象方法,不能有具体方法)。接口是由全局常量或公共的抽象方法所组成。
格式:
权限修饰符(public/缺省的)interface 接口名{
}
2.说明:
- 接口和类是并列存在的关系。
- 接口不能被实例化
- 接口中只能有常量和抽象方法(JDK1.8之前)
- 接口和接口之间是继承关系而且是多继承。 接口1 extends 接口2,接口3…
- 类和接口的关系是实现关系而且是多实现。 类 implments 接口1 ,接口2…
- 类实现接口后必须重写接口中的所有抽象方法,如果不想重写那么该类可以变成抽象类
- 接口和类之间的多态性
3.接口在jdk1.8之后(包括1.8)中的新特性:
接口中可以有 : 常量,抽象方法,静态方法,默认方法
4.说明:
- 如何调用接口中的静态方法:接口名.静态方法名
- 如何调用接口中的默认方法 :实现类的对象.默认方法名
- 类优先原则 :一个类继承的父类和实现的接口(默认方法)中有同名同参的方法,那么调用的是父类中的。
- 接口冲突 : 一个类实现多个接口,多个接口(默认方法)中有同名同参的方法,这时就会发生接口冲突。
- 解决接口冲突 : 实现类只需要去重写该方法即可。再通过该类的对象调用此方法时调用的是重写的方法。
- 实现类重写接口中的默认方法后调用接口中的默认方法:接口名.super.默认方法名
public class InterfaceTest {
public static void main(String[] args) {
C c = new C();
c.print1();
}
}
interface A{
public abstract void print1();
public abstract void print2();
public abstract void print3();
}
//抽象类可以选择性实现抽象方法,但是未实现的抽象方法必须由子类实现,或者同包下的其它类文件实现
abstract class B implements A{
public void print1(){
System.out.println("AAA");
}
}
class C extends B{
public void print2(){
System.out.println("BBB");
}
public void print3(){
System.out.println("CCC");
}
}
java中一个接口是不 允许继承抽象类的,但是允许一个接口继承多个接口
格式
interface 子接口 extends 父接口A, 父接口B,…{
}
//接口的多继承
interface A{ //默认public权限,可省略
public String AUTHOR = "Jerry"; //定义全局常量,省略写法
// public staitc final String AUTHOR = "Jerry"; //定义全局常量,完整写法
public abstract void printA(); //定义抽象方法,省略写法
}
interface B{
public abstract void printB(); //定义抽象方法
}
interface C extends A,B{ //定义接口C, 同时继承接口A、B
public abstract void printC();
}
class X implements C{ //子类实现接口C
public void printA(){
System.out.println("A、Hello World");
}
public void printB(){ //覆写接口B中的printB()方法
System.out.println("B、Hello SDD");
}
public void printC(){
System.out.println("C、Hello DD"); //覆写接口B中的printB()方法
}
}
public class InterfaceDemo06{
public static void main(String args[]){
X x = new X();
x.printA();
x.printB();
x.printB();
}
}//子接口继承父接口,那么实现子接口的时候必须覆写子、父接口中所有的抽象方法
接口:由全局常量和抽象方法组成,默认是public权限,同抽象类相同也是由子类实现。因为接口中的方法默认是抽象方法,所以子类实现接口时必须覆写所有接口中的方法。
抽象类:由abstract关键字定义的方法是抽象方法,包含一个抽象方法的类是抽象类,默认是public权限。抽象方法只需要申明,不需要实现,也就是没有{}主体内容。抽象类如果要使用必须由子类继承,而且子类必须覆写所有定义为abstract的抽象方法。
·如果一个抽象类实现了接口中一部分方法,另一个类继承自抽象类,那么子类必须实现抽象类中未实现的抽象方法
package com.bob.annotation;
public interface Usb {
public abstract void methoud1();
public abstract void methoud2();
public abstract void methoud3();
public abstract void methoud4();
}
//实现接口中的部分方法
abstract class Print implements Usb{
@Override
public void methoud1() {
System.out.println("implments method1.");
}
@Override
public void methoud2() {
System.out.println("implments method2.");
}
}
//继承抽象类Print
class Test extends Print {
public static void main(String[] args) {
Test test1 = new Test();
test1.methoud1();
}
//实现抽象类中未实现的方法
@Override
public void methoud3() {}
@Override
public void methoud4() {}
}
总结:·抽象类肯定可以实现接口。这不是有没有意义的事情, 是一种思想,当你自己写的类想用接口中个别方法的时候(注意不是所有的方法),那么你就可以用一个抽象类先实现这个接口(方法体中为空),然后再用你的类继承这个抽象类,这样就可以达到你的目的了,如果你直接用类实现接口,那是所有方法都必须实现的.
三、类的成员之 : 代码块
1.格式 : {}
代码块分类 :静态代码块 and 非静态代码块
2注意 : 代码块只能使用static修饰,不能final修饰。
2.1 静态代码块:
- 静态代码块是随着类的加载而加载的。(类加载只加载一次)
- 类加载优先于对象的创建。(静态代码块的执行优先于非静态代码块)
- 静态代码块可以有多个,多个静态代码块之间是从上向下依次执行
- 静态代码块 : 不能调用实例变量和非静态方法
- 对Java类进行初始化
2.2 非静态代码块
- 非静态代码块是随着对象的创建而加载的
- 非静态代码块的执行优先于构造器
- 非静态代码块可以有多个,多个非静态代码块之间是从上向下依次执行
- 非静态代码块 : 可以调用静态方法和类变量
- 对Java对象进行初始化
3.思考 :什么时候使用代码块?
静态代码块:随着类加载而执行的代码放在静态代码块中。
非静态代码块:只要创建对象时就会执行的代码放在非静态代码块中。
public class Test {
/**
* 静态代码块
*/
static{
System.out.println("执行静态代码块...");
}
/**
*非静态代码块
*/
{
System.out.println("执行构造代码块...");
}
/**
* 无参构造函数
*/
public Test(){
System.out.println("执行无参构造函数...");
}
/**
* 有参构造函数
* @param id
*/
public Test(String id){
System.out.println("执行有参构造函数...");
}
public static void main(String[] args) {
System.out.println("----------------------");
new Test();
System.out.println("----------------------");
new Test("1");
}
}
-----------
Output:
执行静态代码块...
----------------------
执行构造代码块...
执行无参构造函数...
----------------------
执行构造代码块...
执行有参构造函数...
四、类的成员之:内部类
1.内部类 : 在一个类A的内部再定义一个类B,类A叫作外部类,类B叫作内部类。可以分为成员内部类 和局部内部类。
成员内部类 可分为: 静态(成员)内部类and非静态(成员)内部类
2.内部类:
作为类:
1.可以继承父类,实现接口
2.类内部可以有类的成员(普通类可以做的事情内部类都可以)。
作为类的成员:
1.可以被static修饰
2.可以使用四种权限修饰符
3.内部类还可以调用外部类的成员(属性,方法)
3.学习目标:
1.如何创建内部类的对象?
1.1 静态内部类:new 外部类名.内部类名()
1.2 非静态内部类 :外部类的对象.new 内部类名()
2.内部类如何调用外部类的成员(属性和方法)?
2.1 静态内部类 :外部类名.类变量名、静态方法 (只能调用外部类的类变量和静态方法)
2.2 非静态内部类 : 外部类名.this.属性名、方法名
/**
* 外部类、内部类定义
*/
public class Outer {
private int outerVariable = 1;
/**
* 外部类定义的属性(重名)
*/
private int commonVariable = 2;
private static int outerStaticVariable = 3;
static {
System.out.println("Outer的静态块被执行了……");
}
/**
* 成员方法
*/
public void outerMothod() {
System.out.println("我是外部类的outerMethod方法");
}
/*
* 静态方法
*/
public static void outerStaticMethod() {
System.out.println("我是外部类的outerStaticMethod静态方法");
}
/**
* 静态内部类
*/
public static class Inner {
/**
* 成员信息
*/
private int innerVariable = 10;
private int commonVariable = 20;
static {
System.out.println("Outer.Inner的静态块执行了……");
}
private static int innerStaticVariable = 30;
/**
* 成员方法
*/
public void innerShow() {
System.out.println("innerVariable:" + innerVariable);
System.out.println("内部的commonVariable:" + commonVariable);
System.out.println("outerStaticVariable:"+outerStaticVariable);
outerStaticMethod();
}
/**
* 静态方法
*/
public static void innerStaticShow() {
//被调用时会先加载Outer类
outerStaticMethod();
System.out.println("outerStaticVariable"+outerStaticVariable);
}
}
/**
* 外部类的内部如何和内部类打交道
*/
public static void callInner() {
System.out.println(Inner.innerStaticVariable);
Inner.innerStaticShow();
}
}
4.匿名内部类的特点
1.匿名内部类必须继承父类或实现接口
2.匿名内部类只能有一个对象
3.匿名内部类对象只能使用多态形式引用
调用局部内部类
public class outer {
public void out(){
int i=2;
class Inner{
int a=1;
public void inner(){
System.out.println(a);
}
}
Inner in=new Inner();
in.inner();
}
}
匿名对象调用局部内部类
public class outer {
public void out(){
int i=2;
class Inner{
int a=1;
public void inner(){
System.out.println(a);
}
}
new Inner().inner();
}
}
注意 匿名对象没有引用变量,只能使用一次,每次创建一个匿名对象都在堆中分配内存,都具有不同的内存地址。
创建多了比较浪费资源。