类与对象
类有成员+方法
public class MyClass{private int i;MyClass(int value){i = value;}public void add(){this.i++;}public void get(){return i;}}
实例化
类可实例化成对象,除了静态方法和成员,只有实例化成对象才能使用。
抽象类
继承
关键字extends
子类会继承父类带有的变量和方法
子类只可继承自一个父类
子类可以在原有父类所带有的变量和方法的基础上,增加其他方法或成员
通过@Override注解,可对父类的方法进行重写。
public class Animal{private int age;public void eat(){// do something;}public void sleep(){// do something;}}public class Dog extends Animal{@Overridepublic void eat(){System.out.println("eat");}public void eat(String food){System.out.println("eat " + food);}@Overridepublic void sleep(){System.out.println("sleep");}}
接口
- 关键字
interface定义接口 接口可以定义成员变量和方法
- 成员变量一定是
final常量,默认用final与static修饰,无需显式声明,且定义时,必须赋值public interface FatherI{// 成员变量,已用final修饰int a = 1;// 定义方法,默认已使用public abstract 修饰,实现类必须将方法进行实现void sleep();}
- 成员变量一定是
类使用关键字
implements实现接口- 接口使用关键字
extends拓展一个或多个的接口 在Java8中,为接口引入
静态和默认方法,这时候接口与抽象类的界限变得模糊起来。- 默认方法用
default关键字修饰,通过实现类的实例化对象才能进行调用 静态方法用
static关键字修饰,可直接通过接口调用- 在Java9中可用
private修饰,默认为public,private的静态方法只能在接口中访问,即使是在接口的实现类中也不可使用 ```java public interface FatherI{ // 抽象方法,必须被实现类重写(除非实现类是抽象类) void abstractMethod(); // 静态方法 public static void staticMethod(){ System.out.println(“test-FatherI-staticMethod”); } // 私有静态方法 private static void privateStaticMethod(){ System.out.println(“test-FatherI-staticMethod”); } // 默认方法,可被实现类重写 //访问权限为public,我很好奇在后面的版本会不会增加private修饰 default void defaultMethod(){ // 私有静态方法,只可接口内部访问,所以只有接口中实现的方法才可以调用 FatherI.privateStaticMethod(); } } public class FatherImpl implements FatherI{
@Override public void abstractMethod(){ System.out.println(“test-abstractMethod”); }
public static void main(String[] args) { FatherImpl fatherImpl = new FatherImpl();
// 可用,通过实现类的实例化对象调用重写的方法 fatherImpl.abstractMethod();
//!!!不可用,通过实现类调用接口静态方法 FatherImpl.staticMethod();
//!!!可用,调用接口静态方法 FatherI.staticMethod();
//!!!不可用,在其他类中调用私有静态方法 FatherI.privateStaticMethod();
// 可用,通过实现类的实例化对象调用接口默认方法 fatherImpl.defaultMethod();
} } ```- 在Java9中可用
- 默认方法用
如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。 ```java public class FatherC{ private int age; public void test(){
System.out.println("test-FatherC")
} }
public interface FatherI { // 接口默认方法 public default void test(){ System.out.println(“test-FatherI”) } }
public class Son extends FatherC implements FatherI{ private String name; }
public class Main{ public static void main(String[] args){ Son son = new Son(); son.test(); // 输出 test-FaC // 会优先调用父类FaC的test()方法 } }
- 一个类可以实现多个接口,可以弥补抽象类的单继承设计```javapublic interface FatherIA{void sleep();default void defaultMethod(){System.out.println("defaultMethod-FatherIA");}}public interface FatherIB{void sleep();default void defaultMethod(){System.out.println("defaultMethod-FatherIB");}}public class FatherImpl implements FatherIA,FatherIB{@Overridepublic void sleep(){System.out.println("sleep");}// 当实现的多个接口,具有相同的默认方法(与方法重载类似),实现类必须自行实现@Overridepublic void defaultMethod(){System.out.println("defaultMethod-FatherImpl");}}
封装
隐藏对象的内部状态和功能,仅对外提供公共访问方式。
如下所示,name和height属性都设为私有,防止通过person.height直接访问对象的属性,而允许通过get/set方法进行访问和修改的方式,就是一个典型的封装行为。
class Person {private String name;private double height;private int age;public void setName(String name){this.name = name;}public String getName(){return name;}public void setHeight(double height){if(height < 0){return;}this.height = height;}public double getHeight(){return height;}public void setAge(int age){if(age < 0){return;}this.age = age;}public int getAge(){return age;}public boolean isAdult(){return age >= 18;}}class Test{public static void main(String args[]){Person person = new Person();// 不可用person.height = 1.70;// 可用person.setHeight(1.70);}}
好处
- 可以隐藏内部细节,对外提供公共访问方式,提高安全性
- 在
setHeight时,可以对height的值进行验证,隐藏了内部细节,提高了安全性。
- 在
提高代码的复用性
- 还是考虑上面的代码,当其他类调用
Person的isAdult()方法时,直接调用即可得到结果,当有一天法定成年年龄发生改变,只需改变isAdult()的实现,而调用者则无需做出任何更改。多态(重载与重写)
多态的定义还挺有争议的,有人把方法重载也算进在,这里也采取这种广义的理解(尽管我觉得不算👀。
Java中分为编译时多态(即方法重载Overload)和运行时多态(即方法重写Override)编译时多态(重载)
编译时多态即是方法/运算符的重载,Java中并不支持运算符重载(但我觉得未来可期:>)
同一个事物在不同的情况下具有不同的行为,比如当传入的参数的个数,类型这些不同时,进行不一样处理,这称为多态。
当有多个具有相同名称但参数不同的方法时,则这些方法称为重载。方法可以通过参数数量的更改或/和参数类型的更改来重载。public class MyClass{private int i;public void add(){i++;}public void add(int a){i+=a;}}
运行时多态(重写)
简单来说是同一个类的对象,做同一件事,表现出不同的行为。
以下图为例
- 还是考虑上面的代码,当其他类调用
Shape为父类,Cirle和Square为子类,均实现了draw()方法和move()方法ShapeController类具有drawShape()方法,接受一个shape类型的参数```java public class Shape{ void draw(){
} void move(){System.out.println("draw-default");
} } class Circle extends Shape { @Override public void draw(){System.out.println("move-default");
} @Override public void move(){System.out.println("draw-circle");
} } class Square extends Shape{ @Override public void draw(){System.out.println("move-circle");
} @Override public void move(){System.out.println("draw-square");
} } class ShapeController{ public static void main(String[] args){System.out.println("move-square");
} public void drawShape(Shape shape){Circle circle = new Circle();Square square = new Square();drawShape(circle);drawShape(square);
} }shape.draw();
```javapublic class Shape{void draw(){System.out.println("draw-default");}void move(){System.out.println("move-default");}}class Circle extends Shape {@Overridepublic void draw(){System.out.println("draw-circle");}@Overridepublic void move(){System.out.println("move-circle");}}class Square extends Shape{@Overridepublic void draw(){System.out.println("draw-square");}@Overridepublic void move(){System.out.println("move-square");}}class ShapeController{public static void main(String[] args){Circle circle = new Circle();Square square = new Square();drawShape(circle);drawShape(square);}public void drawShape(Shape shape){shape.draw();}}
// todo
- 编译器在编译时,并不直接能确定传入
drawShape()方法的参数具体是什么类型,只能确定传入的一定是Shape类型。那这时候,通过Shape s = new Circle();的方式,创建一个Circle对象,调用ShapeController的drawShape(s)方法,这时候会调用Circle类重写的draw方法,同理,当传入一个Square类给drawShape(s),会调用Square类的draw方法。同一个对象,在传入对象不同的自动进行不同行为即为多态。
为了解决这个问题,面向对象程序设计语言使用了
后期绑定的概念,当向对象发送消息时,被调用的代码直到运行时才能确定。编译器确保被调用方法的存在,并对调用参数和返回值进行类型检查,但是并不知道将被执行的确切代码。 为了执行后期绑定,Java使用一小段特殊的代码来代替绝对地址的调用。这段代码使用对象中存储的信息来计算方法体的地址。这样,根据这一小段代码的内容,每一个对象都可以具有不同的行为表现。当向一个对象发送消息时,该对象就能直到对这条消息该做些什么 ——《Java编程思想》第四版,第一章第9页,陈昊鹏译 评论👀:”向对象发送消息”,不知道是原文如此还是译者自己的译法,这句好实在不好理解 不过总的来说,在这儿提到多态的是实现机制的,还是很受用, 之前觉得多态这种行为是很自然的,理所应该,那实现起来应该也很简单,没想到实现机制还挺复杂
