类的继承
1、继承是发在多个类之间的
2、继承使用关键字extends
3、只允许单继承,允许多层继承
4、被继承的叫父类。继承父类的叫子类
5、父类中只有非私有属性和方法可以被继承
6,构造方法不能被继承
7、创建对象会调用构造方法,调用构造方法不一定会创建对象
8、调用带参数构造方法用super()
没有构造方法
- 子类继承父类的属性和方法,私有属性或方法不能被继承
- extends关键字是用来继承的
- class 子类名 extends 父类名{ }
带无参构造方法
构造方法不能被继承,创建子类对象父类的构造方法也会被调用,无参构造方法可以只在父类中写,子类中可以不写。
带有参构造方法
带有参数的构造方法必须在两个类中都写,
super关键字可以在子类的构造方法中显示地调用父类的构造方法,super()必须为子类构造函数中的第一行。
接口(interface)
在Java编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface关键字来声明。
接口可以包括常量、方法签名和默认方法。常量在接口中被隐式的声明为public static final,而方法签名则是public abstract。默认方法是指在Java 8之后添加的一种方法,允许在接口中提供默认的实现方法,而不需要让实现类必须去覆盖该方法。
Java接口的组成:
接口定义:使用interface关键字来定义接口,其中包含了方法签名和常量等元素;
实现类定义:实现类通过implements关键字来实现接口,并提供具体的实现代码;
调用者代码:调用者可以直接使用接口类型来引用任意一个实现类对象,并调用接口中定义的方法。
接口的格式
把定义类中的class换成interface就可以了
public interface 接口名称{
//抽象方法,以下四种都可以
public abstract void method1();
public void method2();
abstract void method3();
void method4();
}
接口的使用
- 接口不能直接使用,必须要有一个“实现类”实现该接口,实现该接口中的所有方法;
- 接口与类之间通过implements来实现
接口的特性
-
接口是一种引用类型,但是不能直接通过new接口的对象。
-
接口中的方法只能用public修饰
-
接口中的方法不能在接口中实现
-
重写接口时,不能用默认的访问权限
-
接口中的变量默认被final public static修饰
-
接口中不可以有静态代码块,构造方法
-
接口虽然不是类,但接口编译后的字节码文件也是.class
-
如果类没有实现接口中所有的抽象方法,则必须设置成抽象类
接口之间的继承
在Java中,类与类之间是单继承,一个类可以继承多个接口,接口与接口可以实现多继承。利用接口可以实现多继承的目的。相当于把多个接口拼在一起。
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
// 两栖的动物, 既能跑, 也能游
interface IAmphibious extends IRunning, ISwimming {
}
class Frog implements IAmphibious {
...
}
java代码块
代码块是类的成分之一:成员变量,方法,构造器,代码块,内部类。
在Java中,使用 { } 括起来的代码被称为代码块
代码块的分类
- 局部代码块:用于限定变量生命周期,及早释放,提高内存利用率。
- 静态代码块:主要用于对静态属性进行初始化。
- 实例(构造)代码块:调用构造方法都会执行,并且在构造方法前执行。
局部代码块
在方法中出现,可以限定变量生命周期,及早释放,提高内存利用率。
示例:
public class Test1{
public static void main(String[] args) {
//局部代码块
{
int n = 100;
}
// 局部代码块中声明的变量在代码块外部访问不到!
// System.out.println(n);
}
}
静态代码块
必须有static修饰,必须放在类下。与类一起加载执行。并且静态代码块执行一次
示例:
public class Test2 {
public static String name;
// 静态代码块
static {
// 初始化静态资源
name = "张三";
System.out.println("静态代码块执行...");
}
public static void main(String[] args) {
System.out.println("main方法执行...");
System.out.println(name);
}
}
特点
- 每次执行类,加载类的时候都会先执行静态代码块一次。
- 静态代码块是自动触发执行的,只要程序启动静态代码块就会先执行一次。
- 在启动程序之前可以做资源的初始化,一般用于初始化静态资源。
实例代码块(构造代码块)
没有static修饰,必须放在类下。与对象初始化一起加载,即每次调用构造方法都会执行,并且在构造方法前执行。
示例:
public class Test3{
private String name;
// 实例代码块。 无static修饰。
{
System.out.println("实例代码块执行...");
name = "张三";
}
// 构造器
public Test3(){
System.out.println("无参构造方法执行...");
}
// 有参数构造器
public Test3(String name){
System.out.println("有参构造方法执行...");
this.name = name;
}
public static void main(String[] args) {
Test3 t1 = new Test3();
Test3 t2 = new Test3("李四");
System.out.println(t1.name + t2.name);
}
}
特点
- 无static修饰。属于对象,与对象的创建一起执行的。
- 每次调用构造器初始化对象,实例代码块都要自动触发执行一次。
- 实例代码块实际上是提取到每一个构造器中去执行的。
- 实例代码块中的内容在构造方法前执行。
静态代码块、构造代码块、构造函数执行顺序
父类静态代码块 > 子类静态代码块 > main()方法 > 父类代码块 > 父类构造器 > 子类代码块 > 子类构造器
匿名对象
即没有声明变量名称的变量,比如,假设我们有一个Person类,此时
public static void main(String[] args)
{
new Person(); --->即为匿名对象
}
匿名对象的好处:
- 匿名对象最大的好处就是可以节省代码量,在代码只运行一次的情况下十分有用。
- 匿名对象还可以当作参数传递,可以用于实现一些函数接口的作用。
匿名对象的限制:
要了解匿名对象的限制,首先要简要介绍Java的垃圾回收机制,与C和C++不同,Java中创建的实例对象不需要手动释放内存,Java中的垃圾回收机制会不定时地将其清理。
所以说,当一个对象要被反复调用时,使用匿名对象的效率就会很低。
何时被清理:
Java中除基本类型外,其他的对象都是引用类型。如果当一个对象不再被引用,JVM就 会将其标记为垃圾,此时我们就无法再使用对象。
内部类
在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。内部类的出现,再次打破了Java单继承的局限性。
内部类一般分为4种:成员内部类、静态内部类、局部内部类和匿名内部类。
内部类的位置
- 成员内部类:定义在外部类的内部,类似于成员方法,类和成员都不能使用static修饰
- 静态内部类:定义在外部类的内部,类似于静态方法,类使用static修饰,成员也可使用static修饰
- 局部内部类:定义在外部类的某一作用域内部(如静态代码块、代码块、静态方法、普通方法),类和成员都不能使用static修饰
- 匿名内部类:定义在外部类的任意位置(如静态变量、成员变量、静态代码块、代码块、静态方法、普通方法),类和成员都不能使用static修饰
内部类与外部类的依赖
- 成员内部类:依赖外部类,需要通过外部类对象来创建成员内部类的实例对象
- 静态内部类:不依赖外部类,可直接创建静态内部类的实例对象
- 局部内部类:与外部类无关,只能在该局部位置内创建局部内部类对象
- 匿名内部类:与外部类无关
内部类可以拥有的成员
- 成员内部类:可拥有非静态的成员,可使用任何修饰符修饰
- 静态内部类:可拥有任何的成员(静态、非静态),可使用任何修饰符修饰
- 局部内部类:可拥有非静态的成员,可使用任何修饰符修饰
- 匿名内部类:可拥有非静态的成员,可使用任何修饰符修饰
成员内部类
成员内部类是最普通的内部类,它的定义为位于另一个类的内部。类似于成员方法,成员内部类不能拥有静态域但是可以访问外部类的静态部分。
- 定义在外部类的内部,类似于成员方法,类和成员都不能使用static修饰
- 依赖外部类,需要通过外部类对象来创建成员内部类的实例对象
- 可拥有非静态的成员,可使用任何修饰符修饰
- 可以访问外部类任何的成员(静态、非静态),可以是任何修饰符修饰的
- 外部类想要访问成员内部类的成员,需要先创建成员内部类实例对象,再通过实例对象去访问
- 内部类使用成员时,当外部类的成员和内部类的成员重名时,会发生隐藏现象(外部类的成员会被隐藏),默认情况下访问的是内部类的成员(就近原则)
- 外部类和内部类在编译后是两个不同的class文件,内部类的class文件名称:外部类名$内部类名.class
格式:外部类名.内部类名 成员内部类对象名 = new 外部类名().new 内部类名()
静态内部类
静态内部类也是定义在另一个类里面的类,使用static修饰,类似于静态方法,静态内部类不需要外部类对象产生就能使用,静态内部类只能访问外部类的静态部分,不能访问外部类的实例部分。
- 定义在外部类的内部,类似于静态方法,类使用static修饰,成员也可使用static修饰
- 不依赖外部类,可直接创建静态内部类的实例对象
- 可拥有任何的成员(静态、非静态),可使用任何修饰符修饰
- 可以访问外部类静态的成员,可以是任何修饰符修饰的
- 外部类可访问静态内部类的静态成员,可以是任何修饰符修饰的;
- 外部类想要访问静态内部类的非静态成员,需要先创建静态内部类实例对象,再通过实例对象去访问。
- 内部类使用成员时,当外部类的成员和内部类的成员重名时,会发生隐藏现象(外部类的成员会被隐藏),默认情况下访问的是内部类的成员(就近原则)
- 外部类和内部类在编译后是两个不同的class文件,内部类的class文件名称:外部类名$内部类名.class
格式:外部类名.内部类名 成员内部类对象名 = new 外部类名.内部类名()
局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内,类似于局部变量。
- 定义在外部类的某一作用域内部(如静态代码块、代码块、静态方法、普通方法),类和成员都不能使用static修饰
- 局部内部类与外部类无关,只能在该局部位置内创建局部内部类对象
- 可拥有非静态的成员,可使用任何修饰符修饰
- 若定义在静态部分中,可以访问外部类静态的成员,可以是任何修饰符修饰的;
- 若定义在非静态部分中,可以访问外部类任何的成员(静态、非静态),可以是任何修饰符修饰的
- 外部类不可访问局部内部类成员
- 内部类使用成员时,当外部类的成员和内部类的成员重名时,会发生隐藏现象(外部类的成员会被隐藏),默认情况下访问的是内部类的成员(就近原则)
- 外部类和内部类在编译后是两个不同的class文件,内部类的class文件名称:外部类名$编号+内部类名.class
格式:局部内部类名 局部内部类对象名 = 局部内部类名();
匿名内部类
匿名内部类可以看作是特殊的局部内部类,其本质就是一个继承/实现了某个类(接口,普通类,抽象类)的子类匿名对象。
- 匿名内部类没有名称,没有构造函数,且使用者无法创建构造函数,但是实际上JDK为匿名内部类生成了构造函数
- 定义在外部类的任意位置(如静态变量、成员变量、静态代码块、代码块、静态方法、普通方法),类和成员都不能使用static修饰
- 匿名内部类与外部类无关
- 可拥有非静态的成员,可使用任何修饰符修饰
- 若定义在静态部分中,可以访问外部类静态的成员,可以是任何修饰符修饰的;
- 若定义在非静态部分中,可以访问外部类任何的成员(静态、非静态),可以是任何修饰符修饰的
- 外部类想要访问匿名内部类的成员,需要能拿到匿名内部类实例对象,再通过实例对象去访问(但也只能访问当匿名内部类的父类原有成员,若是匿名内部类自定义的成员则还是无法访问)。
- 外部类和内部类在编译后是两个不同的class文件,内部类的class文件名称:外部类名$编号.class
格式:new 接口名|类名(){重写方法}
如果重写方法为非必要的,原则上是可以没有重写方法部分的。