JVM中的对一个对象的所有初始化动作,是javac在字节码文件中帮我们生成的
1.成员变量的显式初始化
2.初始化代码块(构造代码块)
3.构造方法
初始化静态的东西
在Java中,一个没有方法体的方法应该定义为抽象方法,而如果一个类中含有抽象方法,则该类必须定义为一个抽象类
抽象方法和抽象类语法:
1.抽象类和抽象方法必须使用abstract(修饰符)声明
2.抽象方法不能有方法体(连定义方法的{}都没有)
3.抽象类不一定有抽象方法,但是含有抽象方法的类必定是抽象类
4.抽象类不能实例化(但是多态机制可以用子类实例化)
a.通过抽象类的子类来实例化子类
抽象类的子类(二选一)
1.如果不想重写抽象类里面的抽象方法,则子类必须是抽象类
2.如果不是抽象类,则必须实现抽象父类的所有抽象方法
方法覆盖的条件
1.方法签名必须完全一样
2.方法返回值类型,兼容(要么一样, 要么子类类型)
3.访问权限子类权限>=父类权限
==尤其注意,即使一个类中没有抽象方法,我们也可以将其定义为抽象类,因为有的时候,出于各种各样的原因,你不想让别人直接实例化你的类对象==。
抽象类不能被实例化,即不能使用抽象类的构造函数创建对象(java语法),抽象类中可以声明抽象方法,除此之外抽象类与一般的类没有区别。
1.抽象类只定义类的部分行为,这些行为是子类共有的(具体行为可以和抽象行为共存)
2.其他行为(抽象方法)由子类实现的抽象方法提供,因此抽象类通常作为一个框架
3.将子类将实现的抽象方法组织起来,简化或限制子类的设计
抽象类的成员特点:
1.抽象类的成员变量:既可以变量,又可以是常量(和普通类没有任何区别)
2.抽象类的构造方法(可以):用于子类访问父类数据的初始化
3.抽象类的方法:可以是抽象的,也可以是非抽象的,作用是:
抽象的:(从语法层面)强制子类实现 (类似的有枚举类型 PrameterizedType )
非抽象的:子类可以复用
public class Supplement02 {
public static void main(String[] args) {
// 抽象类本身不能被实例化
//Animal animal = new Animal();
//animal.shout(animal);
// 抽象类不能被直接实例化
// ctrl + 鼠标左键,点击代码产看源代码
//TestAbstractClass testAbstractClass = new TestAbstractClass();
}
}
//class Animal {
//
// public void shout() {
//
// }
//}
//class Dog extends Animal{
// public void shout() {
//// System.out.println("dog shout");
// shout();
// }
//}
abstract class TestAbstractClass{
public void test() {
}
}
abstract class Creature {
int i;
int j;
public Creature() {
}
public Creature(int i, int j) {
this.i = i;
this.j = j;
}
}
//抽象累的子类,不一定必须实现父类中的所有抽象方法,
// 假如抽象类的子类没有实现父类所有的抽象方法,将该子类定义为抽象方法
abstract class Animal extends Creature{
int height;
int weight;
int age;
public Animal(int height, int weight, int age, int i, int j) {
super(i, j); //各司其职,做好自己本类的事
this.height = height;
this.weight = weight;
this.age = age;
}
public abstract void shout(Animal a);
public Animal testOverride() {
return null;
}
}
abstract class TestAbstractClass{
public void test() {
}
}
class Cat extends Animal {
int k;
public Cat(int height, int weight, int age, int i, int j, int k) {
super(height, weight, age, i, j);
this.k = k;
}
public void shout(Animal a){
System.out.println("cat shout");
}
public void go() {
}
@Override
public Cat testOverride() {
return null;
}
}
接口
什么是接口
一个完全抽象的类,所有的方法都是抽象方法(只存在抽象方法,jdk之前)
接口的使用场景:
通常使用接口来声明,存在这样一些行为,某些不是被所有子类所共有的行为,而是一些特殊群体所共有的行为,使用接口来组织这些抽象行为
实现接口,其实相当于表示的是一个实质上的继承关系
class A implements 接口B 接口B 和 A他们之间是继承关系
public class InterfaceDemo1 {
}
//抽象类Animal
abstract class Animal {
public abstract void shout();
}
//抽象类SpecialBehavior
abstract class SpecialBehavior {
public abstract void arithmetic();
public abstract void go();
}
//接口InterfaceSpecialBehavior
interface InterfaceSpecialBehavior {
public abstract void arithmetic();
public abstract void go();
}
//Cat类继承父类Animal
class Cat extends Animal {
@Override
public void shout() {
System.out.println("cat shout");
}
}
// 在java中,对于同一个类,只能声明该类继承自一个类,但是在java中同一个类可以实现多个接口
class SpecialCat extends Animal implements InterfaceSpecialBehavior{
@Override
public void shout() {
}
@Override
public void arithmetic() {
}
@Override
public void go() {
}
}
接口使用Interface 关键字进行声明(类使用class关键字声明)
格式:interface 接口名{ }
类实现接口使用implements 关键字
格式: class 类名 implements 接口名{ }
接口中是否必须包含抽象方法呢?不一定,比如:空接口
类A implemets 接口B 类A和接口B是继承关系 类A(“继承”)实现接口B
空接口通常被当成是一种标记,比如Serriallizable接口就是一个空接口
if(对象 instanceof 空接口类型){
}
接口无法直接实例化
如何实例化?由其具体的子类实例化
new 接口类型的对象 但是我们new 接口的实现类(接口的子类)
接口的子类(普通类):
1.要么是抽象类(接口的实现类没有实现接口中定义的所有抽象方法)
2.要么重写接口中所有的抽象方法(子类变成一个普通类,从而该普通类可以被实例化)
关系
接口和接口的关系:(继承)
1.接口之间可以相互继承,即可以定义一个接口用extends关键字去继承一个已有的接口
普通类和接口的关系:(实现)
2.可以定义一个类用implements关键字去实现一个接口中的所有方法
抽象类和接口的关系(实现)
可以去定义一个抽象类用implements关键字去实现一个接口中定义的部分方法。
类与类、类与接口的关系:
一个类可以继承一个父类的同时,实现一个或多个接口,extends关键字必须位于implements关键字之前
import java.io.BufferedOutputStream;
import java.io.Serializable;
public class InterfaceDemo2 {
public static void main(String[] args) {
}
}
//空接口 接口中不一定一定包含抽象方法
interface InterfaceDeination {
}
// 接口的使用:通过implents关键字,使用定义好的接口,声明某个类实现该接口
class A implements InterfaceDeination{
}
interface InterfaceNotNull{
//包含抽象方法
public abstract void testInterface();
public abstract void eat();
}
//接口子类的第二种情况:子类为普通类
class SonOfInterNotNull implements InterfaceNotNull{
@Override
public void testInterface() {
}
@Override
public void eat() {
}
}
//接口子类的第1中情况,子类为抽象类
abstract class SonOfInterNotNull2 implements InterfaceNotNull {
@Override
public void testInterface() {
}
}
class Father {
public void beat() {
System.out.println("father beat");
}
}
// 一个类可以在继承另一个类的同时,实现多个接口
class Son extends Father implements InterfaceDeination,InterfaceNotNull {
@Override
public void testInterface() {
}
@Override
public void eat() {
}
}
单亲继承和双亲继承
Java语言中,类(class)只支持单继承,一个类只能有唯一的(直接)父亲
从语法上来看,一个类的声明中,extends关键字之后只能跟一个类名,否则报错:class cannot extends multi class
单重继承,并不意味着某个类各类就只能继承一个类的代码,可以间接继承多个类的代码。
在Java语言中,接口(Interface)可支持多亲继承 ,一个接口可以有多个父接口,子接口拥有所有父接口中声明的方法
1.接口之间有多重继承
public class JavaFrameExtends {
public static void main(String[] args) {
}
}
class GrandFather {
}
class Father1 extends GrandFather{
}
// 这种继承形式才叫多重继承,Java不支持
//class Father2 extends GrandFather, Object{
//
//}
//通过加深继承层次,间接继承多各类的代码
class Son1 extends Father1 {
}
interface FirstInterface {
public abstract void first();
}
interface SecondInterface{
public abstract void second();
}
// 接口确实实现了真正的多重继承
interface ThirdInterface extends FirstInterface,SecondInterface{
}
class TestInterfaceMultiExtends implements ThirdInterface {
@Override
public void first() {
}
@Override
public void second() {
}
}
interface FourthInterface {
}
// 对于普通类来讲,也可以实现多重继承
class ClassMultiExtends extends TestInterfaceMultiExtends implements FourthInterface {
}
在普通类中,java也声称实现了多重继承,如果把实现接口当做是一种继承,那么因为一个普通类,可以在继承一个类的同时,实现一个或多个接口,从这个角度来理解,普通类实现了多重继承(并非真正意义上的多重继承)
但是以上对普通类的多重继承的说明,只针对jdk1.8之前,在jdk1.8中接口中新增了两种方法:
1.默认方法
2.静态方法 (当你要定义工具方法的时候,通常如果是某接口的实现类都需要的,那么就可以在接口中定义静态方法)
这两种方法在接口中,都是可以有方法实现的。
1.在接口中,如果要访问静态方法,如果只通过方法名.来访问的话,只能在定义默认方法的接口中
2.如果使用接口名.的形式来访问静态方法,静态方法在哪里都可以访问到
3.对于默认方法,在子类类体,或者子类对象名.的形式时都可以访问
public class InterfaceDome3 {
public static void main(String[] args) {
AA aa = new AA();
aa.test();
aa.testDefault();
}
}
interface NewMethods {
//默认方法
default void testDefault() {
System.out.println("我是默认方法");
//testStatic();
}
static void testStatic() {
System.out.println("我是静态方法");
}
//public abstract void a();
// 新添加的添加默认方法不会影响,已经实现过接口的类
default void addDefault() {
}
}
interface SonOfNewMethod extends NewMethods{
// 覆盖默认方法, 在子类中不仅可以覆盖,而且还可以把默认方法覆盖成抽象方法
@Override
void testDefault();
}
class AA implements NewMethods{
public void test() {
testDefault();
// testStatic();
NewMethods.testStatic();
}
}
public class HomeWork04 {
public static void main(String[] args) {
A a = new A();
//访问接口的默认方法1—在子类的成员方法中调用
a.test();
//访问接口的默认方法2—在实例化子类对象中用 子类对象名.的形式访问
a.testDefault();
//访问静态方法1:在任何地方使用 接口名.静态方法名 调用
Test.testStatic();
}
}
interface Test {
//默认方法
default void testDefault() {
System.out.println("我是默认方法");
//访问静态方法2:在默认方法中调用静态方法
testStatic();
}
//静态方法
static void testStatic() {
System.out.println("我是静态方法");
}
}
class A implements Test {
public void test() {
testDefault();
}
}
接口中可以声明以下成员:
(1)成员
(2)方法
注意事项:
1.接口中的成员都是public的,不能指定其他的访问控制修饰符
2.接口中的成员变量默认是static final,必须显式初始化,接口中的方法只能提供方法头声明,不能提供实现,且除abstract外,不能使用其他修饰符。
3.接口中的成员变量默认是static final,必须显式初始化
4.接口中的方法只能提供方法头声明,不能提供实现,且除abstract外,不能使用其他修饰符(jdk 8之前)
方法的默认修饰符: public abstract修饰
在接口中,如果不给方法添加访问权限修饰符,那么接口中默认的访问权限全都是public,编译器在字节码文件中会添加public
子接口的域将隐藏父接口中声明的同名域,被隐藏的父接口中的域必须通过父接口名访问
要访问被隐藏的域:父接口名. 访问被隐藏的父接口中的同名域
在接口中也存在着方法的重载和覆盖
在jdk1.8之前接口中的方法覆盖没啥意义是因为接口中不提供方法的实现,但是jdk1.8之后,因为接口新增了了默认方法,该方法有方法可以实现,jdk1.8之后接口中覆盖是有意义的
interface [extend,]
{
[public static final] 数据类型 常量名=常量值;
[public abstract] 返回类型 方法名(参数列表);
}
通过接口可以实现不相关类的相同行为,而不需考虑这些类之间的层次关系
1.完全不同的类可以实现同一个接口(同一个实现同一个接口之后,就可以被看成同一个接口类型)
2.接口实现,不受java中单重继承的限制
接口可以继承多个接口,但不能继承类
public class InterfaceDemo4 {
public static void main(String[] args) {
Interface2.testInterfaceField();
}
}
interface Interface1 {
//private int add(); 不行
int add(); //不行
//protected int add();不行
//public int add();
// 接口中不能定义构造代码块
// {
// }
// 接口中不能定义静态代码块
// static {
// }
// 接口中的成员变量默认被static final修饰
int i = 0;
}
interface Interface2 extends Interface1{
int i = 100;
static void testInterfaceField() {
System.out.println(i);
System.out.println("父接口中的i值: " + Interface1.i);
}
//接口中的抽象方法也可以重载
int add(int a, int b);
int add(int a, int b, int c);
}
class SonOfInterface1 implements Interface1{
@Override
public int add() {
return 0;
}
}
//class SuperSon extends SonOfInterface1 implements Interface2{
//
//}
接口的实现与接口特点
具体类实现一个接口就是要实现该接口的所有方法(抽象类除外)
接口中方法都是抽象的
多个无关的二类
内部类
把类定义在其他类的内部,这个类就被称为内部类
内部类的访问特点:
1.内部类可以直接访问外部类的成员,包括私有。
2.外部类要访问内部类的成员,必须创建对象
public class InnerClassDome1 {
public static void main(String[] args) {
//在外部类中,我们可以通过创建内部类对象,来访问内部类的成员变量
OuterClass outerClass = new OuterClass();
outerClass.accInnerClassField();
}
}
class OuterClass {
//外部类的私有成员变量
private int i;
public void accInnerClassField() {
FirstInnerClass firstInnerClass = new FirstInnerClass();
System.out.println(firstInnerClass.j);
}
//定义在其他类内部的类就叫做内部类
public class FirstInnerClass{
//内部类中的private不影响定义它的外部类对其成员变量的访问
private int j = 100;
public void accOuterPrivateField() {
System.out.println(i);
}
}
}
假设,某pc公司最新最新研制了一款pc,在这个pc,中包含了该公司最高成果,当前全球最厉害的cpu
假设我们用一个类来表示pc,那么同过我们之前学习的知识是无法完成这个需求的:
因为我们如果使用普通类,一旦把普通类的成员 变量的访问权限定义成private,虽然别人访问不到cpu中的成员,但同时,我们自己也访问不到cpu 中的成员
但是如果使用内部类,利用内部类的访问特征:
1.内部类可以直接访问外部类中的成员变量包括私有。(cpu 内存更方便的交互)
2.内部类中可以创建对象的方式,访问内部类成员(包括私有) (我们Pc类,但别的类就访问不了Cpu中的成员)
public class InnerClassSituatation {
}
class PC {
Cpu cpu;
Memoery mem;
public PC(Cpu cpu) {
this.cpu = cpu;
}
public double calculate() {
Cpu cpu = new Cpu();
return 0.0;
}
private class Cpu{
private int core;
private int hz;
private double calculate() {
//cpu的执行流程,制作工艺
return 0.0;
}
}
}
class Memoery {
}
内部类位置
按照内部类在类中定义的位置不同,可以分为如下两种格式:
内部类首先可以被看成是外部类的成员,
1.成员位置(内部成员类):类中其他成员外
2.局部位置(局部内部类):类中方法之内
成员位置内部类:
1.在外部类中如何访问呢?通过普通的创建对象的方式
2.在外部类的外部如何访问内部类?
外部类名.内部类名 对象名= 外部对象.内部类对象
内部成员的常见修饰符
1.private 为了保证数据的安全性
2.static 为了让数据访问更方便
被静态修饰的成员内部类只能外部类的静态成员
内部类被静态修饰后的方法
非静态方法:外部类名.内部类名 对象名 = new 外部类名.内部类名();
静态方法:上面创建的对象访问,或者, 外部类名.内部类名.方法名();
public class ClassifyInnerClass {
// 这个类就是外部类的外部
public static void main(String[] args) {
Outer1 outer1 = new Outer1();
outer1.accPrint();
//在外部类的外部,创建内部类对象
//1. 因为,我们定义的内部类,是外部类的一个成员
//2. 成员依赖于对象而存在,即内部类对象依赖于外部类对象而存在
//3. 所以要得到一个内部类对象,必须先创建外部类对象,在外部类对象上,调用创建对象的表达式
// 创建对象的表达式: new 类型(..)
Outer1 outer11 = new Outer1();
//接收内部类对象的引用变量的类型用 外部类.内部类的形式来表示
//Outer1.Inner1 inner1 = outer11.new Inner1();
//当内部类被static修饰符所修饰
Outer1.Inner1 inner12 = new Outer1.Inner1();
}
}
class Outer1 {
int i = 100;
int j = 1000;
public void accInner() {
System.out.println(i);
//在外部类的成员方法中,访问内部类的静态成员方法
Inner1.testStatic();
}
public void accPrint() {
//在外部类中访问内部类
Inner1 inner1 = new Inner1();
inner1.accOuterMethod();
}
//private class Inner1
static class Inner1{
int i = 1000;
//内部类还可以直接访问外部类的成员方法
public void accOuterMethod() {
// accInner();
// System.out.println(j);
}
public static void testStatic() {
}
}
}