面向对象编程
类声明
// 声明Person类
class Person {
// 声明成员属性
private String name;
private int age;
// 声明构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 默认构造方法
public Person() {}
public String getName() {
return this.name;
}
public void setName(String name){
this.name = name;
}
public int getAge() {
return this.age;
}
// 方法重载(即只要参数不同,允许同名方法)
public void greet() {
System.out.println("Hello, world!");
}
public void greet(String name) {
System.out.println("Hello, " + name + "!");
}
public class Main {
public static void main(String[] args) {
// 实例化Person类
Person p1 = new Person();
Person p2 = new Person("zhangsan",19);
}
}
Java中的类声明与Dart中的很相似,主要有以下几点需注意
- Java使用
private关键字修饰类的私有成员,Dart中则以_开头的方式私有化。但对于暴露给外部访问的方法或属性,则必须使用public关键字修饰 - Java存在方法重载机制,只要参数不同,方法名可以相同。因此Java中的类可以定义许多同名的构造方法,但没有命名构造方法。
- Java中创建类的实例对象必须使用
new关键字,不能省略 - Java没有
set、get关键字实现setter和getter机制,setter和getter只是普通的方法。 - Java类中的成员属性有默认值,引用类型的属性默认
null,其他基础数据类型中数值类型默认值是0,布尔类型默认值是false
继承
// 使用extends关键字从Person类继承,可以复用代码,只需要声明自己特有的属性
class Student extends Person {
private int score;
public Student(String name, int age, int score) {
super(name, age); // 使用super调用父类的构造方法
this.score = score;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
Java中亦使用extends关键字来实现继承,但也有一些需要注意的地方:
Java只能单继承,没有类似Dart里面的
mixin混入机制。因此,一个类有且仅有一个父类与Dart一样,
Object类是所有类的超类子类不能访问父类中使用
private关键字修饰的属性和方法。如果父类希望被子类访问,一般使用protected关键字修饰子类中实现父类中的同名方法称为覆写,注意方法重载与方法覆写的区别。方法重载要求两个方法的方法签名不能相同;而覆写要求两个方法的方法签名必须相同,它们唯一相似的地方只是两者都要求这两个方法的方法名相同。
如果一个父类不允许子类对它的某个方法进行覆写,但允许调用,这时可以使用
final修饰该方法如果一个类不希望被其他类继承,那么也可以在声明时用
final修饰,被final修饰的类不能被继承,例如:final class Person {...}
多态
多态指针对某个类型的方法调用,其实际执行方法的取决于运行时期实际类型。表现到代码中,就是在实例化对象时,使用父类指向子类
public class Main {
public static void main(String[] args) {
// 让父类指向子类
Person p = new Student("zhangsan",19,99);
}
}
抽象类
Java中的抽象类与Dart类似。抽象类强迫子类实现其定义的抽象方法,否则编译会报错。因此,抽象方法就相当于一种“规范”,抽象类统一定义这种“规范”,由子类具体实现这些“规范”。所以抽象类不能直接实例化,必须由子类实例化,可以利用多态,实例化时让父类指向这个具体实现的子类。
// 声明一个抽象类,包含一个抽象方法
abstract class Person {
public abstract void greet();
// 抽象类中也可以声明非抽象方法
public String getName() {
return "";
}
}
class Student extends Person {
// 子类覆写抽象方法
@Override
public void greet() {
System.out.println("hello");
}
}
public class Main {
public static void main(String[] args) {
// 父类执行子类
Person p = new Student();
p.greet();
}
}
- Java中,抽象类的抽象方法必须使用
abstract关键字声明,Dart中省略方法体即表示抽象方法。 - 抽象类中也可以定义非抽象方法
- 普通类中也可以定义抽象方法,一旦定义抽象方法,则其子类必须强制实现该方法
接口
实际上接口和抽象类的作用是相似的,如果一个抽象类中的全部方法都是抽象方法,那么这个抽象类就相当于接口。但是,由于Java只能单继承,不能多继承,因此抽象类就有了局限,很多时候,可能需要继承多个类,于是就有了接口。Java中的类可以实现多个接口。
// 声明一个接口
interface Person {
// 定义方法签名,不能有方法体
void greet();
String getName();
}
注意,一般接口都写到一个单独的源码文件中
// 一个类实现一个接口
class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
@Override
public void greet() {
System.out.println("hello");
}
@Override
public String getName() {
return this.name;
}
}
public class Main {
public static void main(String[] args) {
// 接口指向具体实现类,多态
Person p = new Student("zhangsan");
p.greet();
}
}
注意早期Java接口中只能定义方法签名,不能有方法实现
Java的接口之间是可以继承的,并且可以多继承
public interface A { void a(); } public interface B { void b(); } // 一个接口可以继承多个接口 public interface Test extends A,B { void c(); }Java 8新特性,接口中可以添加使用
default或者static修饰的方法
内部类和匿名内部类
将一个类声明到另一个类的内部(嵌套声明),那么这个类就是内部类。对于内部类,需要注意,内部类可以调用外部类中的属性和方法,反过来,外部类不能调用内部类中的属性和方法。Dart语言中是没有内部类的。
// 外部类
class Outer{
private String str ="外部类成员属性";
//声明一个内部类
class Inner{
private String inStr= "内部类成员属性";
public void print(){
//访问外部类的属性
System.out.println(str);
}
}
public void func(){
//创建内部类对象
Inner in = new Inner();
in.print();
}
}
public class Test{
public static void main(String[] args){
// 实例化外部类对象
Outer out = new Outer();
out.func();
// 在外部实例化一个非静态内部类,必须先实例化这个内部类的外部类
Outer.Inner in = new Outer().new Inner();
}
}
匿名内部类是一个没有名字的在方法中声明的内部类。Java中没有闭包,这种匿名内部类写法,相当于的Dart中的闭包。
interface Work{
void run();
}
abstract class Human{
public abstract void eat();
}
public class Test{
public static void main(String[] args){
// 创建一个匿名内部类,实现run方法,并实例化,同时调用run方法
new Work(){
public void run(){
System.out.println("run");
}
}.run();
new Human(){
public void eat(){
System.out.println("eat");
}
}.eat();
}
}
需要特别注意:
- 匿名内部类必须继承一个类或者实现一个接口
- 匿名内部类没有类名,因此没有构造方法
- 匿名内部类访问局部变量时,局部变量必须使用
final修饰(JDK 8之前)
静态成员和静态方法
类中声明的普通属性,称为成员属性或成员变量;而使用static修饰的成员则称为静态成员。普通成员变量在每个实例对象中都有自己的一个独立“空间”,但静态成员只有一个共享“空间”,类的所有实例对象都会共享该成员变量。因此我们可以直接通过类名去访问静态成员变量,而不需要先实例化该类。
class Person {
public static int number = 18;
public static void setNumber(int value) {
number = value;
}
}
public class Main {
public static void main(String[] args) {
// 类名直接访问
System.out.println(Person.number);
Person.setNumber(20);
}
}
类中使用static修饰的方法称为静态方法。同理,静态方法通过类名直接调用,无需实例化。
需要注意:静态方法中,只能访问static修饰的静态成员,不能访问非静态成员。
static拓展:静态代码块
class Hello {
// 静态代码块:独立于类成员的static语句块,不在任何的方法体内
// 在字节码被加载时执行,只会执行一次,因此优先于类的构造方法执行。
static {
System.out.println("Static code block");
}
}
包
Java中将一种名字空间,称之为包:package。一个类总是属于某个包,类名(比如Person)只是一个简写,真正的完整类名应是包名.类名
包名,其实就是源码所在文件夹的路径(src作为源码根目录,包名从src之后开始),同一个包之内的范围,称为包作用域。我们使用import导入相关包下面的类。
什么是jar包?
我们知道源码需要编译成.class文件,这些字节码文件散落在各级目录中,不便管理,这时就需要把那些目录打成一个包方便管理。jar包实际上就是一个zip压缩文件而已,我们可以手动用zip压缩目录,然后将压缩包后缀名改为.jar,这样就手动生成了一个jar包,但是不建议手动去做这种事,因为jar包中通常还需要一个配置文件MANIFEST.MF来描述main函数入口。
访问控制
在Java中共有四种访问控制,即public、protected、private和缺省,使用这些修饰符可以限制访问作用域。

类型转换
当两个类型可以强制类型转换时,可以用括号的方式强转,否则就会报错
public class Main {
public static void main(String[] args) {
Person p = new Student("zhangsan",19,99);
// 强制类型转换
Student stu = (Student)p;
}
}
包装类
Java是一门面向对象的编程语言,然而却存在8种基本数据类型,这些基本数据类型显然不是面向对象的,在使用泛型之类的特性时,就存在缺陷,为了解决这个问题,Java在1.5版本时,提出了包装类的概念。
所谓包装类,就是将八种基本数据类型转化为对象类型。显然的,Dart语言在设计时就避免了这种问题,因此Dart中没有基本数据类型,即使是数值,也是用对象类型来表示。

需要注意,包装类是一个类,所以是引用数据类型,它的零值是null
// 基本数据类型转包装类型
Integer num = new Integer(18);
Double pi = new Double(3.14);
// 包装类型转基本数据类型
int n = num.intValue();
double p = pi.doubleValue();
// 还可直接隐式转换
int l = num;
double q = pi;
枚举
Java中的枚举与Dart中有些相似,也可用于switch条件分支中
// 声明一个颜色枚举
enum Color { RED, ORANGE, YELLOW, GREEN, CYAN, BLUE, PURPLE }
enum Week { Mon, Tue, Wed, Thu, Fri, Sat, Sun }
公众号“编程之路从0到1”