一.面向对象
1.1 封装
Java中封装可以用一句话总结“属性私有结合get/set进行访问”
1.2 继承
1.2.1单继承
Java使用extends关键字实现单继承,而Java中所有类都会继承Object类,在Object类中有9种方法(如下图)会被所有类直接调用或者重写。
1.2.1.1 super关键字
在继承中常用的关键字是super,super可以理解成指向父类的指针
当指向父类的构造函数时,super让我们可以少在子类申明一些和父类重复的成员变量,例如
public class Father {
String name;
int age;
public Father(){
System.out.println("父类的无参构造");
}
public Father(String name,int age){
this.name=name;
this.age=age;
}
}
public class Son extends Father {
String department;
public Son(String name, int age, String department){
super(name,age);
this.department=department;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getDepartment() {
return department;
}
}
public class Test {
public static void main(String[] args) {
Son son=new Son("张三",22,"研发部");
System.out.println(son.getName()+"---"+son.getAge()+"----"+son.getDepartment());//张三---22---研发部
}
}
以上我们使用super在子类的构造中调用是不是就省去了一些变量的申明了呢。 而当super不指向父类的构造方法的时候可以使用super.方法名/变量名的方式直接调用父类的成员方法或者成员变量 以上面的代码为例子,若在Son类要定义一个方法想调用Father类的show方法时,可以如下
public class Son extends Father {
...
public void method(){
System.out.println(super.name);
super.show();
}
}
//这样子类调用method方法的时候可以直接使用父类的成员变量和成员方法了
1.2.1.2 抽象类
抽象类是使用abstract修饰的类,类中可以有具体方法也可以有抽象方法,其中抽象方法需要使用abstract修饰,抽象方法都只有方法申明没有方法实现。抽象类不能使用new关键字实现,只能让子类进行继承,继承抽象类的子类必须实现抽象类中的所有抽象方法。
1.2.2 多继承
多继承也就是接口的实现。接口的设计算是面向对象的精髓了。 接口有以下一些准则:
- 当类实现接口的时候,类要重写接口中所有的方法。否则,类必须声明为抽象类
- 接口中定义的变量,必须用public static final修饰,修饰符默认存在,可以不写。
- 所有方法都使用public修饰,可以省略
public interface MyInterface {
//抽象方法,可以省略public abstract
void abstractMethod();
//默认方法,可以有方法体
default void defaultMethod(){
System.out.println("接口中的默认方法");
}
//静态方法,可以有方法体,可以使用接口名直接调用
static void staticMethod(){
System.out.println("接口中的静态方法");
}
//私有方法,供给接口内部的默认方法和静态方法调用,这样可以避免代码的重复
private void privateMethod(){
System.out.println("接口中的私有方法");
}
}
1.3 多态
Java中的多态指的是同一个方法根据调用方法的对象的不同实现的功能则不同。这是由于在创建对象时 A a=new A()的左边可以不同,左边代表着对象的引用类型,左边可以是右边的父类引用类型,从而可以实现了多态。
多态发生有三个条件
- 有继承关系
- 有方法重写
- 父类引用指向子类对象
//父类
public class Father {
public Father(){}
public void say(){
System.out.println("父类的say方法没有被重写过");
}
public void show(){
System.out.println("父类的show方法被子类重写过");
}
}
//子类
public class Son extends Father {
public Son(){}
public void show(){
System.out.println("子类重写了show方法");
}
public void run(){
System.out.println("子类独有的run方法");
}
}
//测试
public class Test {
public static void main(String[] args) {
Object object=new Son();
Father father=new Son();
Son son=new Son();
father.show();
son.show();
father.say();
son.say();;
((Son) father).run();
}
}
//执行结果如下
//子类重写了show方法
//子类重写了show方法
//父类的say方法没有被重写过
//父类的say方法没有被重写过
//子类独有的run方法
如上代码所示,当Father类和Son有继承关系,且new出来的Son分别指向了Father和Son之后,若Son类重写了Father类的方法,那么无论是father还是son都会执行重写后的方法(father.show和son.show的执行结果是一样的)。如果没有重写(father.say方法),则会执行父类的方法。
在多态中还有一个知识点就是上下转型,类似与基本数据类型的转换,即上面代码中的以下两行
son.say();
向上转型,低转高,自动转换,将son自动从Son类型转化成Father类型
((Son) father).run();
向下转型,高转低,强制转换,将father从Father类型强制转换为Son类型
二.内部类
首先,学过JS的同学都了解过函数式编程,个人看来,内部类就算是一种函数式编程,虽然他不是那么的纯。内部类细分为成员内部类,局部内部类,静态内部类,匿名内部类,下面就分别为大家介绍
2.1 成员内部类
成员内部类的定义就是将一个类做为外部类的成员方法或者成员变量来看待。 例子:
class Outer {
private int age=20;
class Inner{
public void show(){
System.out.println(age);
}
}
}
public class Test {
public static void main(String[] args) {
Outer.Inner inner=new Outer().new Inner();
inner.show();
}
}
在上面的代码中明显的Inner像是Outer类的一个成员变量或者成员方法的意味,所以我们在创建的时候,他的类型就是Outer.Inner,一般创建形式如下
外部类.内部类 xxx=new 外部类().new 内部类();
2.2 局部内部类
和成员内部类不同的是,局部内部类是定义在外部类方法中的类, 例子
class Outer{
private int age=20;
public void method(){
class Inner{
public void show(){
System.out.println(age);
}
}
Inner inner=new Inner();
inner.show();
}
}
public class Test {
public static void main(String[] args) {
Outer outer=new Outer();
outer.method();
}
}
例子中局部内部类的使用已经很清楚了,这也和JS的语法很像。
2.3 静态内部类
static一般情况下是不能用于修饰类的,但是静态内部类除外。
普通的内部类的创建是如下
外部类.内部类 xxx=new 外部类().new 内部类();
而静态内部类的创建如下
外部类.内部类 xxx=new 外部类().内部类();
不用使用new关键字创建内部类,这样内部类更像是外部类的一个属性
在静态内部类中,不能使用外部类的非static修饰的成员变量和成员方法
2.4匿名内部类
匿名内部类就是指内部类直接被new出来,没有具体的名字。匿名内部类的前提是必须继承一个类或者实现一个接口。例如
//Runnable接口被直接new之后立即重写了run方法,简化了代码
public class Test {
public void Go(String s){
Thread thread=new Thread(new Runnable() {
@Override
public void run() {
System.out.println(s);
}
});
thread.start();
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
Test test=new Test();
test.Go("线程"+i);
}
}
}