面向对象
面向对象对应的就是面向过程,
面向过程就是一步一步去操作,你需要知道每一步的步骤。
面向对象的编程以对象为核心,通过定义类描述实体及其行为,并且支持继承、封装和多态等特性
面向对象基础
面向对象编程,是一种通过对象的方式,把现实世界映射到计算机模型的一种编程方法。
现实世界中,我们定义了“人”这种抽象概念,而具体的人则是“小明”、“小红”、“小军”等一个个具体的人。所以,“人”可以定义为一个类(class),而具体的人则是实例(instance):
class Test {
private int field1;
public String field2;
// 构造函数
public Test(String field2, int field1) {
this.field1 = field1;
this.field2 = field2;
}
public int getField1(){
return this.field1;
}
public void setField1(int val){
if(val < 0 || val > 100){
// 抛出错误
throw new IllegalArgumentException("invalid age value");
}
// 赋值
this.field1 = val;
}
};
public class Main {
public static void main(String[] args){
Test t = new Test();
t.setField1(2);
System.out.println(t.getField1());
System.out.println(t.field2);
}
}
写法同js类型,但是需要指定Test类型。一般字段使用private修饰符修饰,表示私有属性,外部无法访问,但是可以通过设置公共的方法去获取和设置值。
java类的构造函数,是public 类名(){},跟js的constructor(){}还是有点区别的。并且java可以写多个构造方法。除此之外,构造方法之间还能相互调用。
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name) {
this(name, 18); // 调用另一个构造方法Person(String, int)
}
public Person() {
this("Unnamed"); // 调用另一个构造方法Person(String)
}
}
方法重载
如果有一系列方法,它们的功能都是类似的,只有参数有所不同,那么,可以把这一组方法名做成同名方法。
方法重载的目的是,功能类似的方法使用同一名字,更容易记住,因此,调用起来更简单。
public void setField1(int val){
if(val < 0 || val > 100){
// 抛出错误
throw new IllegalArgumentException("invalid age value");
}
// 赋值
this.field1 = val;
}
public void setField1(int val, boolean isTrue){
if(val < 0 || val > 100){
// 抛出错误
throw new IllegalArgumentException("invalid age value");
}
// 赋值
this.field1 = val;
}
比如String.indexOf()方法,就提供了多种调用方法。
举个例子,String类提供了多个重载方法indexOf(),可以查找子串:
int indexOf(int ch):根据字符的Unicode码查找;
int indexOf(String str):根据字符串查找;
int indexOf(int ch, int fromIndex):根据字符查找,但指定起始位置;
int indexOf(String str, int fromIndex)根据字符串查找,但指定起始位置。
继承
所有的类都默认继承与object,只有object例外,他没有父类。
java的继承同js差不多,只有一点区别,这里不多详述。
多态
子类可以重写父类的方法。这里需要注意,只有方法名,参数,返回值相同,才算是重写。加上@Overide装饰器可以方便编译器检查报错。
class Person {
public void run() {
System.out.println("Person.run");
}
}
class Student extends Person {
@Override
public void run() {
System.out.println("Student.run");
}
}
多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法;
没运行之前不知道运行的是父类的方法还是子类的方法。
如果父类不想子类继承某个方法,可以用final修饰方法。
class Person {
protected String name;
public final String hello() {
return "Hello, " + name;
}
}
用final修饰的类不允许被继承
用final修饰的属性,不允许被重新赋值
抽象类
如果父类的方法本身不需要实现任何功能,仅仅是为了定义方法签名,目的是让子类去覆写它,那么,可以把父类的方法声明为抽象方法:
abstract class Person {
public abstract void run();
}
包含抽象方法的类不允许被实例化。抽象类强迫子类必须实现他的抽象方法。
用法跟ts类似,这里不多详述
面向抽象编程的本质就是:
- 上层代码只定义规范(例如:abstract class Person);
- 不需要子类就可以实现业务逻辑(正常编译);
- 具体的业务逻辑由不同的子类实现,调用者并不关心。
接口
没有字段的,且全部方位都是抽象方法的抽象类,就可以改写为接口。
abstract class Person {
public abstract void run();
public abstract String getName();
}
//改写为
interface Person {
void run();
String getName();
}
接口定义的所有方法默认都是public abstract的
而当一个具体的类想去实现一个接口的时候,就需要使用implements,而非extends。
一个类只能继承于一个类,但是一个类可以implements多个接口。
接口之间也可以通过extends去继承。
接口还可以定义一个非抽象方法default,这个不强求类去实现,目的是为了:
当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。
静态字段和静态方法
实例字段在每个实例中都有自己的一个独立“空间”,但是静态字段只有一个共享“空间”,所有实例都会共享该字段。举个例子:
class Person