java几乎是最好面向对象的语言了,和C++相比,你会感觉到java的面向对象部分是多么简洁。
面向对象概念
在真实的世界里,不管是我们人,还是动物,还是机器,我们都可以称之为一个对象,他们都有共同的特点,这个特点是,他们都是一堆属性的集合,所以,我们把拥有一堆属性的集合体,称为一个对象。例如,人,可以有名字,可以有年龄,可以有性别等等属性,如果我们抽象出来,那么就是一个对象,在java中如何定义一个对象呢?
public class Person{
int age;
String name;
char sex;
}
这样就构造了一个Person对象,例如,我们把它定义成,诸葛先生。
public static void main(String[] args) {
Person person = new Person();
person.name = "诸葛先生";
person.age = 20;
person.sex = '男';
}
如果你以后想使用这个对象,那么只需要将person传递过去就可以了。
但是,久而久之,我们发现,直接通过person.name = “”这种通过 ‘.’直接调用属性或赋值属性,是非常不安全的,例如,我们只希望这个诸葛先生,只能被赋值,而不能被取值,那么应该怎么办呢?接下来,请看对象的访问权限
对象的访问权限
如果我们只希望,我们定义一个诸葛先生对象,但是,不想透露他的年龄,那么我们该怎么做呢?
在java中,提供了三种权限控制的关键字,这个跟C++中几乎是一模一样的。
public 公共的,可以直接为外部提供服务
private 私有的,不能直接为外部提供服务,只能为自己内部使用
protected 保护的,该关键字用在继承中,到后面讲到继承的时候再来讲这个关键字。
让我们来重新定义这个类
public class Person {
private int age;
private String name;
private char sex;
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public void say(){
System.out.println("我是" + this.name);
}
}
我们照样的定义一个person对象
Person person = new Person();
person.setAge(20);
person.setName("诸葛先生");
person.setSex('男');
这样,我们同样的构造了一个诸葛先生对象,但是,你会发现,这里的三个属性都被private修饰了,而且,age没有被提供get方法,这时候,你就没有办法听过person.age或者person.getAge()来获取到诸葛先生的真实年龄了,这也就是一种权限控制策略,心细的同学可能会发现,上面多了一个this,这又是什么呢?事实上,this就是指的当前对象。如果你定义的是person1对象,那么this就是代表的person1对象,如果你定定义的是person2对象,那么this就是代码的person2对象,也就是说,这个this指代的是字节。
构造函数
有人会说,上面这中初始化方法,太麻烦了,我们构造一个诸葛先生对象,居然要在后面调用3次person….啥的,有没有更简单一点的方法?答案是有的。
public class Person {
private int age;
private String name;
private char sex;
public Person(int age,String name,char sex){
this.age = age;
this.name = name;
this.sex = sex;
}
public String getName() {
return name;
}
public char getSex() {
return sex;
}
public void say(){
System.out.println("我是诸葛先生");
}
}
这时候,我们在使用的时候
Person person = new Person(20,"诸葛先生",'男');
System.out.println(person.getName());
构造函数的命名规则是名字必须和类名相同,没有返回值,如果构造函数前面不写public,那么默认的权限的包权限,也就是同一级目录下才能使用,否则就会new失败,在C++中,如果我们在构造函数前面什么都不写,编译器默认修饰成private,而在java中,我们称它为default
继承
我们前面学了类和对象,如果我们希望某个类复用其他类的属性和方法,那么可以使用继承来实现。
public Animal{
protected String name;
protected char sex;
public void setName(String name){
this.name = name;
}
public void setSex(char sex){
this.sex = sex;
}
public void getName(){
return this.name;
}
public void getSex(){
return this.sex;
}
public void say(){}
}
public Dog extends Animal{
public void say(){
System.out.println("汪");
}
}
public Cat extends Animal{
public void say(){
System.out.println("喵");
}
}
我们定义了一个Animal对象,同时让dog和cat继承于animal,这时候,这个两个类中也就包含了animal中的方法了,但是如果, animal中是用private修饰的,那么将不会继承这个属性或方法。
Cat cat = new Cat();
car.setName("阿猫");
System.out.println(cat.getName);
Dog dog = new Dog();
dog.setName("阿狗");
System.out.println(dog.getName());
使用继承的时候,构造函数的执行顺序
我在使用继承的时候,事实上,是先执行父类的构造函数,然后再执行子类的构造函数,在内存中,事实上,存在两个对象,两个对象都被同一个标识符引用。
public class Test extends Test2{
public Test(){
super("哈哈");
System.out.println("我是子类的构造方法");
}
public static void main(String[] args) {
System.out.println(new Test().getName());;
}
public int getNum(){
return 1;
}
}
class Test2{
protected String name;
public Test2(String name){
this.name = name;
System.out.println("我是父类的构造方法");
}
public String getName(){
return this.name;
}
public int getNum(){
return 1;
}
}
你会发现,上面先打印的是我是父类的构造方法,再打印的我是子类的构造方法,再打印哈哈,这就体系了,先执行的是父类的构造方法,如果我们不写这个super(“哈哈”),那么这个端程序是有问题的,如果不写,编译器会帮我们自动调用父类中午参构造方法,我们知道,如果我们在父类中定义了其他有参构造方法,那么,就不会再默认定义一个无参构造方法了,不管怎么样,先被调用的都是父类的构造函数。
父类引用指向子类对象
有上面的例子,
我们完全可以这么做,让父类引用指向子类对象。
Test2 t = new Test();
System.out.println(t.getNum());
上面打印的是2,而不是1,也就是说,如果子类和父类中有相同的方法,那么调用是执行的子类中的方法,而不是父类中的方法,这就是多态,你想想,如果很多类都继承这个Test,都有一个getNum()方法,是不是想要调哪个类中的方法,我们就new哪个类就可以了?我们根本不必关系要用哪个类来引用了,因为他们统统都可以用父类来引用。拿上面哪个动物的例子来说明吧。
cat和dog都继承了animal,而我们现在有如下一个函数
public static void listen(Animal animal){
System.out.println("我听到有动物在喊" + animal.say());
}
你会发现,你如果我们使用这个方法,根本不用关心传过来的是dog还是cat,它都能调用say();方法,有了这个,我们是不是就可以实现定义好一套接口,供后面的人使用,我也不知道对方要在say里面写什么,但是,我这里确实可以调用对方的say方法,这就是多态的神奇之处,你会发现,它居然可以调用未来别人定义的方法。事实上,这个地方在C++快速入门中也有解释,只不过在C++中要使用virtual关键字修饰,否则就不会产生多态,调用的是自身的方法。
抽象类
含有抽象方法的类叫抽象类,抽象方法,也就是一个方法模板,里面没有实现,在上面的例子你会发现,我们在Animal中什么都没有写,这时候,就可以定义成一个抽象方法。
抽象类的定义方法
public abstract class Animal{
protected String name;
protected char sex;
public void setName(String name){
this.name = name;
}
public void setSex(char sex){
this.sex = sex;
}
public void getName(){
return this.name;
}
public void getSex(){
return this.sex;
}
public abstract void say();
}
在抽象类中,可以有抽象方法,也可以有普通方法。
#
接口
如果一个类中,全部是抽象方法,我们可以将它定义成一个接口,接口的定义方法是
public interface A{
public void say();
}
实现这个接口
public class B implements A{
@Override
public void say(){
System.out.println("hello");
}
}
那么,定义成接口有什么好处呢?为什么不使用继承呢?原因是,使用接口,同样的可以实现多态,在java中,只允许单继承的方法,所以如果你这里继承了,以后就没有位置继承了,这里定义成接口,为程序的可拓展性奠定了基础。