一、浅谈为何学习Java
24年本科毕业,从事电气工程师的岗位至今,工作内容愈发让自己觉得无聊。工作中接触到web开发的同事,便对此感兴趣。在学习过程中也验证了这个点,抛开之后是否能靠学这个转行不谈,投入到学习编程的过程中,能让我忘记时间、忘记疲惫,全身心地投入到其中。这也是我取名JustForFun的原因,希望在此过程中能收获快乐,并且能坚持下去。
二、对面向对象的理解
Java基础已经基本学的差不多了,个人觉得面向对象较为重要,并且有几个点不是很好理解,记录一下自己的理解,深入学习后继续更正
面向对象编程(Object-Oriented Programming,简称OOP)是一种编程思想,将具有相同或类似属性、方法的对象抽象为一个类。面向对象有3个核心概念:封装、继承、多态。
1. 封装
封装比较好理解,将程序的核心功能封装在一个“黑匣子”里面,只给用户暴露使用的接口。
假设有这样一个场景,我们要定义两个人,他们有名字、年龄,并且会做自我介绍,按照面向过程的思路,应该这样实现:
public class Main {public static void main(String[] args) {// person1String p1Name = "小明";int p1Age = 18;// person2String p2Name = "小红";int p2Age = 20;introduce(p1Name, p1Age); // 我叫小明, 我今年18岁。introduce(p2Name, p2Age); // 我叫小红, 我今年20岁。}public static void introduce(String name, int age) {System.out.println("我叫" + name + ", 我今年" + age + "岁。");}}
但是这样,又会暴露一些问题:
1.当我要定义再多一点人时,我需要重复定义新的name和age,每新增一个人,我都需要写一遍introduce(name, age)
2.introduce()
这个方法应该是属于person
的,因为只有人会做自我介绍(不考虑人工智能之类的),但如果我定义一个dogName = "旺财"; dogAge = 3
,我同样可以调用introduce()
,让一只狗做自我介绍,这明显是不对的。
在这种情况下,因为所有的人都有名字、年龄这两个属性,都有自我介绍这个行为或者方法,所以我可以将人抽象为一个类Person
:
class Person {public String name;public int age;Person() {}Person(String name, int age) {this.name = name;this.age = age;}public void introduce() {System.out.println("我叫" + name + ", 我今年" + age + "岁。");}
}
那么对于以上问题,我们可以这样解决:
public class Main {public static void main(String[] args) {Person[] persons = {new Person("小明", 18),new Person("小红", 20),new Person("小花", 18),new Person("小李", 19)};persons[3].age = 65536;for (Person p: persons) {p.introduce();}/*我叫小明, 我今年18岁。我叫小红, 我今年20岁。我叫小花, 我今年18岁。我叫小李, 我今年65536岁。*/}}
我不需要每次新增一个人,都去写一遍introduce()
方法。同样的,由于introduce()
被封装到Person
类里了,其他的小狗小猫就无法调用这个函数了。
但是还存在问题,类里的属性是public的,意味着用户可以随意对这些属性进行更改,可能就会出现一个人65536岁的可能,这是不符合逻辑的。所以封装另一个思想就是只保留有限的接口给用户,而把内部复杂、核心的内容给隐藏起来:
class Person {private String name; // 私有化private int age; // 私有化Person() {}Person(String name, int age) {this.name = name;setAge(age);}public void introduce() {System.out.println("我叫" + name + ", 我今年" + age + "岁。");}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {// 防止用户输入非法年龄this.age = (age >= 0 && age <= 130)? age: 0;}
}public class Main {public static void main(String[] args) {Person[] persons = {new Person("小明", 18),new Person("小红", 20),new Person("小花", 18),new Person("小李", 19)};// persons[3].age = 65536; 这句话编译已经无法通过了persons[3].setAge(65536);for (Person p: persons) {p.introduce();}/*我叫小明, 我今年18岁。我叫小红, 我今年20岁。我叫小花, 我今年18岁。我叫小李, 我今年0岁。*/}}
我们可以根据用户的输入,在内部通过我们自己的规则进行处理,而非把所有权限暴露给用户,让用户可以随意更改
2.继承
当我们需要使用一个共同的类,但是又要有所特点时,就要用到继承。还是以Person
类举例,根据职业,我们可以将人分为教师、学生等等,虽然都属于人这个大类,但每个小类都有自己不同之处。教师、学生都继承于人,拥有人的共同特点,但又因为职业不同,拥有属于自己的特点:
class Teacher extends Person {Teacher() {}Teacher(String name, int age) {super(name, age);}public void teach() {System.out.println(super.getName() + "正在教书");}
}class Student extends Person {Student() {}Student(String name, int age) {super(name, age);}public void study() {System.out.println(super.getName() + "正在学习");}
}public class Main {public static void main(String[] args) {Teacher teacher = new Teacher("王老师", 29);Student student = new Student("小明", 18);// 都能够调用父类的public方法teacher.introduce(); // 我叫王老师, 我今年29岁。student.introduce(); // 我叫小明, 我今年18岁。// 调用自己的方法teacher.teach(); // 王老师正在教书student.study(); // 小明正在学习}}
3.多态
个人人为多态是面向对象最不好理解,也是最有趣的点,感觉多态就是面向对象最核心的概念。多态按照解释叫做:同一个行为在不同对象上表现出不同的形态。父类Person
具有introduce()
方法,子类Teacher
和Student
都可以直接调用,进行自我介绍。但这样的自我介绍又太干巴了,希望子类在介绍自己的同时,可以说明一下自己的职业,此时就需要对继承于父类的方法进行重写:
class Teacher extends Person {Teacher() {}Teacher(String name, int age) {super(name, age);}public void teach() {System.out.println(super.getName() + "正在教书");}// 重写父类方法@Overridepublic void introduce() {System.out.println("我叫" + super.getName() + ", 我今年" + super.getAge() + "岁, 我是一名老师。");}
}class Student extends Person {Student() {}Student(String name, int age) {super(name, age);}public void study() {System.out.println(super.getName() + "正在学习");}// 重写父类方法@Overridepublic void introduce() {System.out.println("我叫" + super.getName() + ", 我今年" + super.getAge() + "岁, 我是一名学生。");}
}public class Main {public static void main(String[] args) {Teacher teacher = new Teacher("王老师", 29);Student student = new Student("小明", 18);teacher.introduce(); // 我叫王老师, 我今年29岁, 我是一名老师。student.introduce(); // 我叫小明, 我今年18岁, 我是一名学生。}}
同一个行为introduce()
在不同对象上表现出不同的形态,这就是多态。多态有个很妙的设定,叫做父类对象指向子类的引用,Person person = new Student()
。还是以学生和老师为例,我现在建立一个函数introduceYourself(obj)
,希望传入里面的obj对象能做一个自我介绍,那这个obj对象,应该是老师,还是学生呢?如果我写成introduceYourself(Teacher teacher)
的话,所有老师都可以传入其中进行自我介绍,但是学生呢?除了老师以外的Person呢?因为对象类型不同,无法传入函数。同样的,这个obj对象我指明是学生的话,也会出现同样的情况。
所以最好的方法应该将对象类型指明为他们的父类Person
:
public class Main {public static void main(String[] args) {Teacher teacher = new Teacher("王老师", 29);Student student = new Student("小明", 18);introduceYourself(teacher); // 我叫王老师, 我今年29岁, 我是一名老师。introduceYourself(student); // 我叫小明, 我今年18岁, 我是一名学生。}public static void introduceYourself(Person person) {person.introduce();}}
父类对象Person,指向了子类Teacher和Student的引用,而由于他们都具有同样的introduce()方法,并且子类已经进行重写,此时父类会调用子类的方法,从而实现同一行为的不同表现。(静态方法不适用该情况,静态方法仍会调用父类的方法,具体原理还不懂)
三、总结
第一次写这么多内容,可能会有很多理解是错误或者不全面的,后面再做订正。