java面向对象基础

在java中,除了基本的数据类型,其他的基本都是类,
比如接口,异常等等…

构造函数

和c++类似,构造函数是用来初始化的实例中的字段的,实例就是对象,字段在这里代表的是类中的数据.没有返回值,而且和类名相同.

比如:

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
	this.name = name;
	this.age = age;
    }
    
    public String getName() {
	return this.name;
    }

    public int getAge() {
	return this.age;
    }
}

这里的Person(String name ,int age)就是一个构造函数,调用构造函数必须用new:

Person p = new Person("Xiao Ming", 15);
    System.out.println(p.getName());
    System.out.println(p.getAge());

和c++类似,java类中都会有默认构造函数,没有参数,也没有执行语句:

 class Person {
    public Person() {
    }
}

通过Person p = new Person()来创建一个实例,但是如果已经定义了其他的构造函数,那么就不能调用默认构造函数,想要都能使用两个构造函数,只能够把两个构造函数都定义起来.
和c++类似,java中也是有this,功能差不多,都是指向自己的实例.

class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
	this.name = name;
	this.age = age;
    }
    
    public String getName() {
	return this.name;
    }

    public int getAge() {
	return this.age;
    }
}

和c++不太像的是,java类中的字段可以赋值的,如果没有赋值,引用类型的初始值就是null,数值是0,布尔类型就是false;

在java中,创建实例的时候是按照下列顺序进行初始化的:

1.始化字段,例如,int age = 10;表示字段初始化为10,double salary;表示字段默认初始化为0,String name;表示引用类型字段默认初始化为null;

2.构造方法的代码进行初始化。

和c++类似,允许定义多个构造方法,用new操作符调用的时候,通过构造方法的参数数量,数据类型和类型自动区分的.

方法重载

和c++类似,java中可以重载函数,函数名相同,但是各自的参数不同,这就是函数重载.

class Hello {
    public void hello() {
	System.out.println("Hello, world!");
    }

    public void hello(String name) {
	System.out.println("Hello, " + name + "!");
    }

    public void hello(String name, int age) {
	if (age < 18) {
	    System.out.println("Hi, " + name + "!");
	} else {
	    System.out.println("Hello, " + name + "!");
	}
    }
}

在java中,hello类中的返回值都必须是一样的,只有参数不太一样.

继承

在java中,继承基本上都是满足is-a关系的,用extends来实现继承,通过继承来达到代码复用的一个目的.

class Person {
    private String name;
    private int age;

    public String getName() {...}
    public void setName(String name) {...}
    public int getAge() {...}
    public void setAge(int age) {...}
}

class Student extends Person {
    // 不要重复name和age字段/方法,
    // 只需要定义新增score字段/方法:
    private int score;

    public int getScore() {}
    public void setScore(int score) {}
}

不要重新写name,age这些了,直接继承到了子类.而且在java中,如果没有明确写继承哪个类,编译器都会自动加上extends Object,除了Object之外,都会继承一个类.继承树如下:

在这里插入图片描述

和c++不同的是,java只允许一个class继承自一个类,一个类只有一个父类,Object没有父类.

在继承中,子类无法访问父类私有的数据或者私有方法.和c++类似,就出现了protected,可以在子类中使用父类protected中的方法数据,但是在外部还是无法使用protected方法.

例如:

class Person {
    protected String name;
    protected int age;
}

class Student extends Person {
    public String hello() {
	return "Hello, " + name; // OK!
    }
}

super关键字代表的是父类,指向父类.和c++不太一样,java中,子类继承父类,因该是先有父类才有的子类,所以需要对父类先进行初始化,在java中,任何类的构造方法第一条语句就是调用父类的构造方法,如果没有明确的调用父类的构造方法,就会自动加上一句super().如果已经有带参数的构造方法,没有不带参数的构造函数,就会编译失败.

示例类如下:

class Person {
    protected String name;
    protected int age;

    public Person(String name, int age) {
	this.name = name;
	this.age = age;
    }
}

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
	this.score = score;
    }

如果直接创建一个Student类对象,则会失败,因为父类没有创建:

Student s = new Student("Xiao Ming", 12, 89);	// 失败

如果将Student类中的构造函数改成第一句加上super(),也会失败,因为父类没有不带参数的构造函数:

 class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
	super(); 	// 自动调用父类的构造方法
	this.score = score;
    }
}

所以应该改为:

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
	super(name, age);		 // 调用父类的构造方法Person(String, int)
	this.score = score;
    }
}

向上和向下转型

和c++类似,向上转型就是一个引用类型为某个类的变量,可以指向其子类的引用变量

Person p = new Student(); 		// OK!

向下转型就是进行强制转换

Person p1 = new Student(); 	// upcasting, ok
Person p2 = new Person();
Student s1 = (Student) p1; 	// ok
Student s2 = (Student) p2; 	// runtime error! ClassCastException!

应为p1本来就是Student的实例,当然可以直接强制转换赋值给s1,但是p2不行,这是符合面向对象is-a思想的.在java13中,利用instanceof来判断是否属于这个类的.

Person p = new Person();
System.out.println(p instanceof Person); 	// true
System.out.println(p instanceof Student);	 // false

Student s = new Student();
System.out.println(s instanceof Person); 	// true
System.out.println(s instanceof Student);	 // true

Student n = null;
System.out.println(n instanceof Student); 	 // false

多态

多态其实就是在某个实例调用方法的时候, 真正执行的方法取决于运行时的实际方法.

重写方法是实现多态的一种手段,重写是重新写父类的函数,其中返回值,参数,函数名都不变,重载是在一个类中函数名不变,参数变.

public class Main {
    public static void main(String[] args) {
	Person p = new Student();
	p.run(); 	// 执行Student中的run函数.
    }
}

class Person {
    public void run() {
	System.out.println("Person.run");
    }
}

class Student extends Person {
    @Override
    public void run() {
	System.out.println("Student.run");
    }
}

@Override是为了检查是否正确重写.加上final修饰词的类不允许继承.实例如下:

final class Person {
    protected String name;
}

// compile error: 不允许继承自Person
Student extends Person {
}

抽象类

抽象类类似于c++中的ABC,在类前面用abstract和抽象类中的方法也用abstract修饰,继承抽象类的子类必须重写抽象方法,如下所示:

abstract class Person {
    public abstract void run();
}

class Student extends Person {
    @Override
    public void run() {
	System.out.println("Student.run");
    }
}

通过尽量高的父类来实例化一个对象,避免引用实际的子类,称为面向抽象编成.

Person s = new Student();
Person t = new Teacher();
Person e = new Employee();
s.run();
t.run();
e.run();

以上代码不用关心具体类型,是面向抽象编程.

接口

如果一和抽象类没有具体的数据类型,所有的内容都是抽象方法,就可以改写为接口,接口也是类,只不过用interface表示,然后通过implements实现.用new实例化接口,和抽象类的用法很像.例如:

interface Person {
    void run();
    String getName();
}

class Student implements Person {
    private String name;

    public Student(String name) {
	this.name = name;
    }

    @Override
    public void run() {
	System.out.println(this.name + " run");
    }

    @Override
    public String getName() {
	return this.name;
    }
}

接口也是类,也可以继承

interface Hello {
    void hello();
}

interface Person extends Hello {
    void run();
    String getName();
}

default方法可以在接口中实现,存在default方法是因为,如何借口中新增加一个方法,这个接口有很多子类,就必要要逐一添加新方法并实现,而default只需要重写就行了.实现default 的方法只需要在接口方法前面加上default就行了.

interface Person {
    String getName();
    default void run() {
	System.out.println(getName() + " run");
    }
}

class Student implements Person {
    private String name;

    public Student(String name) {
	this.name = name;
    }

    public String getName() {
	return this.name;
    }
}

静态字段和方法.

具体的字段的在独立的空间中,而静态的字段都共享一片空间.

public class Main {
    public static void main(String[] args) {
	Person ming = new Person("Xiao Ming", 12);
	Person hong = new Person("Xiao Hong", 15);
	ming.number = 88;
	System.out.println(hong.number);		// 88
	hong.number = 99;
	System.out.println(ming.number);		// 99
    }
}

class Person {
    public String name;
    public int age;

    public static int number;

    public Person(String name, int age) {
	this.name = name;
	this.age = age;
    }
}

那个具体的对象改变静态字段,所有对象的静态字段也都被修改了,原因是静态字段不是属于每个具体对象,而是属于一个共享的空间.存储示意图如下:

在这里插入图片描述

所以直接用类名.静态字段就可以调用了,静态方法只能用静态字段.而且接口中也可以定义静态字段:

public interface Person {
    public static final int MALE = 1;
    public static final int FEMALE = 2;
}

不加public static final,编译器也会自动加上.

eclipse 下面的folder,Source Folder,package的区别与作用?
folder就是普通的文件夹,而Source Folder拥有普通folder的所有功能,并且Source Folder下的所有java文件都会被编译,package也是特殊的文件夹,package必须放在Source Folder下,存放类,用.隔开,生成相应的包路径.

包类似于c++中的名称空间,用来防止类名冲突的,包就是拿来放类用的,一个类总是属于一个包,所有的java程序都是在包中.如果使用IDE,会自动创建一个Source Folder,在Source Folder可以创建包,使用IDE,在创建包的时候用.隔开就是一个层级,说白了,package,Source Folder,Folder都是目录,只不过职能不同.

文件结构:

在这里插入图片描述

实现上面的文件结构,前两个结构很容易,最后需要在包下面创建一个包,就可以用.隔开,如下:

在这里插入图片描述

实际上用.隔开,已经创建了mr/jun的包结构

在这里插入图片描述

包作用域

在一个类中,我们总会引用其他的类,使用import引入.用其它包的类有三种写法:

比如引进 mr/jun/下的Arrays类,直接在引用变量前面加上完整的类名:mr.jun.Arrays如下,

public class Person {
    public void run() {
	mr.jun.Arrays arrays = new mr.jun.Arrays();
    }
}

或者用import,

import mr.jun.Arrays;
public class Person {
    public void run() {
	mr.jun.Arrays arrays = new mr.jun.Arrays();
    }
}

或者全部引入,

import mr.jun.*;
public class Person {
    public void run() {
	mr.jun.Arrays arrays = new mr.jun.Arrays();
    }
}	

最终编译出来的结果都是加上完整类名,引用类也是有顺序的,如下:

1.如果是完整类名,就直接根据完整类名查找这个class;

如果是简单类名,按下面的顺序依次查找:

2.查找当前package是否存在这个class;

3.查找import的包是否包含这个class;

4.查找java.lang包是否包含这个class。java.lang是基础包

都没找到,则报错.

包作用域是指一个类允许访问同一个包中的没有修饰符修饰的类,以及没有修饰符修饰的字段和方法.包必须完全一致,不能有上下级关系.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值