面向对象三要素
封装:顾名思义,将函数或变量集中定义在类中,而非散乱分布。
继承:扩展类的功能。
多态:在扩展类的功能的基础之上,实现其内部方法的多样性。
多态的本质
针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。
package Project1;class Father { public void Func() { System.out.println("Father's Func"); }}class Child extends Father { @Override public void Func() { System.out.println("Child's Func"); }}public class Project1 { public static void main(String[] args) { Father fat = new Father(); fat.Func(); //输出"Father's Func" Child ch = new Child(); ch.Func(); //输出"Child's Func" Father fat2 = new Child(); //子类向父类进行类型转换,以实现多态 fat2.Func(); //输出"Child's Func" }}
类
关于类的一些基本常识
- 任何类初始化的第一步都是调用构造函数来对类内成员变量进行初始化,如果类内成员变量已经有初始值,那么不会影响构造函数对其的初始化过程。换句话说,就是类内成员变量先初始化一遍,然后调用构造函数再对其初始化一遍。
- Java没有析构函数,类内成员变量的析构由GC(Garbage collection,垃圾回收)控制。
普通类
类内部没有内部类而只有成员变量和成员函数。
局部内部类
局部内部类是嵌套在方法、作用域或代码块内部的内部类。它的定义和使用仅限于其所属的封闭范围内。
局部内部类具有以下特点:
作用范围受限:局部内部类的定义范围仅限于它所在的方法、作用域或代码块内部。在外部无法直接访问该类。
访问权限限制:局部内部类只在所在的封闭范围内可见,对外部是不可见的。其他类无法引用或访问局部内部类。
访问外部变量:局部内部类可以访问其所在封闭范围内的变量,包括方法的参数、局部变量以及所在类的成员变量。但要求这些变量为 final 或 effectively final(即只被赋值一次)。
对象创建:局部内部类只能在其所在的封闭范围内进行实例化,无法在外部单独创建对象。
package Project1;class Test { private int x = 0; public void Func() { class Local_Inner1{ public void Func1() { System.out.println("Local_Inner1"); //输出"Local_Inner1" System.out.println(x); //输出0 } } Local_Inner1 li1 = new Local_Inner1(); li1.Func1(); { class Local_Inner2 { public void Func2() { System.out.println("Local Inner2"); } } } //报错,作用域范围受限 Local_Inner2 li2 new Local_Inner2(); li2.Func2(); }}public class Project1 { public static void main(String[] args) { Test t = new Test(); t.Func(); //无法访问Test的局部内部类 }}
抽象类
类中部分成员函数(不包含构造函数)均为声明而无定义,即抽象方法。且抽象类类名及抽象方法需要用abstract修饰。抽象类中的抽象方法需要通过子类继承并覆写的方式来实现。
package Project1;abstract class Father { public abstract void func(); public void func2() { System.out.println("func2"); }}class Child extends Father { @Override public void func() { System.out.println("func"); }}public class Project1 { public static void main(String[] args) { Child ch = new Child(); ch.func(); //输出"func" ch.func2(); //输出"func2" }}
接口
一种特殊的抽象类,类中只包含成员函数的声明(无需abstract修饰符)。继承接口时使用implements而非extends。
package Project1;interface Father { void func();}class Child implements Father { @Override public void func() { System.out.println("func"); }}public class Project1 { public static void main(String[] args) { Child ch = new Child(); ch.func(); //输出"func" }}
内部类
在类内定义的类(区别于局部内部类),不仅可访问外部类的所有成员函数和成员变量,也可继承其他类,但其本身不能被任何类继承。注意在实例化内部类前必须先实例化外部类。
package Project1;class Outer { private int x = 0; class Inner { public void Func() { System.out.println(x); } }}public class Project1 { public static void main(String[] args) { Outer out = new Outer(); Outer.Inner inn = out.new Inner(); //实例化内部类前必须先实例化外部类 inn.Func(); }}
匿名类
如果需要重写某个类的方法,但又不想专门再写个类继承该类,可使用匿名类。
package Project1;class Test { public void Func() { System.out.println("Test's Func"); }}public class Project1 { public static void main(String[] args) { Test t = new Test() { @Override public void Func() { System.out.println("Anonymous Func"); } }; //注意分号 t.Func(); //输出"Anonymous Func" }}
静态内部类
和内部类类似,但是使用static修饰,称为静态内部类。静态内部类与内部类最大的区别在于不依附于外部类实例即可直接实例化,但是无法像内部类一样可访问外部类的全部成员函数和成员变量。
package Project1;class Outer { private int x = 0; static class Inner { public void func() { System.out.println(x); //报错,因为静态类不包含外部类的this指针 } }}public class Project1 { public static void main(String[] args) { Outer.Inner inn = new Outer.Inner(); inn.func(); }}
关于静态成员函数和静态成员变量
它们和普通的成员函数和成员变量的关系,一句话概括就是:虽然从属于该类但独立于该类。
因为静态成员函数没有this指针,所以静态成员函数无法访问类内中普通的成员函数和成员变量。
静态成员函数和静态成员变量可直接通过类名.成员函数名/变量名的方式直接访问,无需创建对象。
作用域
public:被public修饰的类、接口、方法和变量等成员都可以被任何其他类或对象所访问,无论是在同一个包内还是在不同的包内。
private:只有在定义该成员的类内部才能被访问,无法被同一个包内或者其他包中的其他类或对象所访问。
protected:被protected修饰的类、方法、变量或者接口只能被相同包或其子类中的类或对象所访问,换句话说,protected成员只能在定义它的类的子类中被访问,而不能在同一个包中的其他类或对象中被访问。
default:只能在同一个包内被访问。