1、什么是抽象类?
抽象类是用来捕捉子类的通用特性的。使用 abstract 关键字修饰的类。一般的,抽象类命名,以Abstract作为前缀,见名知义
特点:
1)不能创建实例即不能new一个抽象类(对象调用抽象方法,无方法体,没有意义)。
2)抽象类可以不包含抽象方法,若一旦包含,该类必须作为抽象类。
3)若子类没有实现父类所有的抽象方法,那么子类也得作为抽象类(抽象派生类)。
4)构造方法不能都定义成私有的,否则不能有子类(创建子类对象前先调用父类构造方法)。
5)抽象类不能使用 final 修饰,因为必须有子类,抽象方法才能得以实现。
6)是不完整的类,需作为基类,功能需要子类来实现。
2、抽象方法
使用 abstract 修饰且没有方法体的方法,称为抽象方法。
特点:
1)使用抽象abstract修饰,方法没有方法体,留给子类去实现。
2)抽象方法修饰符不能是 private 和 final 以及 static。(继承/实现,方法覆盖才有意义)
3)抽象方法必须定义在抽象类或接口中。
抽象方法要求子类必须重新覆盖,若子类不覆盖,则子类也声明为抽象类。
3、抽象类和普通类的区别
1)抽象类,也是一个类,可以定义抽象方法(没有方法体的方法).
2)抽象类不能创建对象.
除此之外,其他都一样。
abstract public class Human {
protected String name = "Human";
abstract public void study();
}
public class Student extends Human{
@Override
public void study() {
System.out.println("Student study...");
}
public static void main(String[] args) {
Human human = new Student();
human.study(); //Student study...
System.out.println(human.name);//Human.
}
}
二、final 与 static 修饰符
1、final 修饰符
可以修饰类、方法和变量。
1)final 修饰的类为最终类,该类不能有子类。
只要满足以下条件就可以把一个类设计成final类:
(1)某类不是专门为继承而设计。
(2)出于安全考虑,类的实现细节不许改动。
(3)确信该类不会再被拓展。
比如:java中八大基本数据类型的包装类和String类等,是用 final 修饰的final类.
2)final 修饰的方法为最终方法,该方法不能被子类所覆盖.
什么时候把方法设计为final的呢?
(1)父类在构造器中调用的初始化方法.
(2)父类中提供好的算法业务操作,只应该让子类调用,不能被子类继承.
3)final 修饰的变量为常量,只能赋值一次,值不能再改变。
final是所有修饰符中唯一一个可以修饰局部变量的修饰符。
常量的起名规则:全部由大写字母组成,若干个单词之间用下划线分割,比如:MAX_VALURE。MIN_VALUE.
final修饰基本类型常量:
final int age = 17;//age变量只能被赋值一次.
final修饰引用类型常量:
final User user = new User();
user 所引用堆空间的内存地址值不能改变,引用地址中的内容可以改变。
2、static 修饰符
static 可以修饰成员变量、方法和内部类,它修饰的东西被所有对象所共享,依赖于类,随着类的加载而加载,可通过类名直接调用访问。
类成员(static修饰成员)的特点:
1)随着类被加载进JVM时,同时对类成员初始化并在内存中分配空间。
2)优先于对象存在.(对象是通过new出来的.)
3)被该类的所有对象所共享.
4)直接使用类名调用即可.
static 不能与 this 或 super 一起使用:
static优先于对象存在,static是在加载进JVM就存在了,而this与super是new出来的属于对象.
public class Human {
private String name = "Human";
public String getName() {
return name;
}
}
public class Student {
private final String STUDENT_NUMBER = "NO."+ System.currentTimeMillis();
private static final Human HUMAN = new Human();
public final void study() {
System.out.println("Student study...");
}
public static void main(String[] args) {
Student student = new Student();
student.study(); // Student study...
System.out.println(student.getSTUDENT_NUMBER()); // NO.1563025279841
// HUMAN = new Human(); // 再赋值会报错
System.out.println(HUMAN.getName()); // Human
}
public String getSTUDENT_NUMBER() {
return STUDENT_NUMBER;
}
}
三、代码块
代码块:在程序中类/方法中,使用 {} 括起来的一段代码。在代码块中定义的变量的的作用范围,只在该代码块内有效.
而根据代码块存在的位置与修饰符的不同可分为三类:
1、局部代码块:
在方法中定义的代码块,比如 if{},while,for等语句.
2、初始化代码块(构造代码块):
在类中直接定义,与方法是平行关系,用来做初始化操作。
在创建包含初始化代码块所在类的对象时, 优先于构造器执行,创建N个对象,则执行N次。
开发中,不推荐使用,即使要在创建对象的时候做初始化操作,我们一般在构造器中完成即可.
3、静态代码块:
使用 static 修饰的初始化代码块.
当静态代码块所在类的字节码被加载进JVM时,就立马执行静态代码块,而且只会执行一次。
一般的,做静态资源的初始化,加载文件,加载资源.
静态代码块优先于 main 方法执行(main方法,是在字节码被加载进JVM之后,再调用的)。
成员属性的初始化顺序:
先静态后非静态
先声明后赋值
先字段后构造方法
先父类后子类
public class Student {
public Student() {
System.out.println("构造器。。。");
}
{
System.out.println("初始化代码块。。。");
}
static {
System.out.println("静态代码块。。。");
}
public static void main(String[] args) {
System.out.println("main 方法。。。");
new Student();
new Student();
new Student();
}
}
内部类可以看做是外部类的一个成员,那么内部类可以使用 public/缺省/protected/private 修饰,还可以是static修饰。
1、为什么使用内部类:
1)增强封装,把内部类隐藏在外部类之内,不许其他类访问内部类。
2)内部类能提高代码的可读性和可维护性,把小型类嵌入到外部类中结构上代码更靠近。
3)内部类可以直接访问外部类的成员。
一般在开发中什么时候使用内部类.
1)这个类只需要让当前的外部类访问.
2)匿名内部类.
2、内部类根据使用的修饰符不同或者位置不同,可分为四种:
对于每个内部类来说,Java 编译器会生成独立的 .class 文件
1)非静态内部类/实例内部类:外部类名$内部类名.class
没有使用static修饰,说明非静态内部类属于外部类的对象,不属于外部类本身。
特点:
(1)创建实例内部类前,必须存在外部类对象,通过外部类对象创建内部类对象(当存在内部类对象时,一定存在外部类对象).
Outter.Inner in = new Outter().new Inner();
(2)实例内部类的实例自动持有外部类的实例的引用,内部类可以直接访问外部类成员(看反编译).
(3)外部类中不能直接访问内部类的成员,必须通过内部类的实例去访问.
(4)实例内部类中不能定义静态成员,只能定义实例成员.
(5)如果实例内部类和外部类存在同名的字段或方法xxx时,那么
在内部类中使用 this.xxx 表示访问内部类成员.
在内部类中使用 外部类对象.xxx 表示外部类成员.
在外部类中使用 this.xxx 表示访问外部类成员.
2)静态内部类: 外部类名$内部类名.class
内部类使用static修饰。
特点:
(1)静态内部类的实例不会自动持有外部类的特定实例的引用,在创建内部类的实例时,不必创建外部类的实例.
Outter.Inner in = new Outter.Inner();
(2)静态内部类可以直接访问外部类的静态成员,如果访问外部类的实例成员,必须通过外部类的实例去访问.
(3)在静态内部类中可以定义静态成员和实例成员.
(4)测试类可以通过完整的类名直接访问静态内部类的静态成员.
3)局部内部类(打死都不用,破坏封装): 外部类名$数字内部类名.class
定义在方法中的内部类,其可见范围是当前方法和局部变量是同一个级别.
局部内部类只能访问 final 修饰的局部变量
特点:
(1)不能使用 public,private,protected,static修饰符.
(2)局部内部类只能在当前方法中使用.
(3)局部内部类和实例内部类一样,不能包含静态成员.
(4)局部内部类和实例内部类,可以访问外部类的所有成员.
(5)局部内部类访问的局部变量必须使用final修饰(在Java8中是自动隐式加上final,但是依然是常量,不能改变值). 原因:
如果方法中的局部变量不使用 final 修饰,存在于方法的内存空间中,
方法调用结束,方法空间就被消化,局部变量也就被销毁了,
使用 final 修饰的变量,表示常量,存放与常量池,方法销毁之后,该常量依然存在,则对象可以继续访问.
4)匿名内部类(Anonymous):外部类名$数字.class
匿名内部类是一个没有名称的局部内部类,适合于仅使用一次的类。
特点:
(1)匿名内部类本身没有构造器,但是会调用父类构造器.
(2)匿名类尽管没有构造器,但是可以在匿名类中提供一段实例初始化代码块,JVM在调用父类构造器后,会执行该段代码.
(3)内部类处理可以继承类之外,还可以实现接口.