面向过程和面向对象
举个栗子理解一下这两个概念吧,设想一个场景: 你要去找某个学校的张三,当然首先你不是这个学校的,假设你也没有带手机,他也没有。
首先先用面向过程的思想分析一下: 你要去找这个同学,那首先你得知道他的姓名等信息,然后通过保安的登记之后进入学校
按照学校的教学区域分块指引或者自己询问遇到的人去找张三啦。
在利用面向对象的想法来分析一下,首先你要找的是这个学校的张三,那他的职业是什么呢?老师?学生?行政?确定职业以后,那就只需要在
符合职业的一群人中就找啦,如果知道张三的性别,那就从那就符合职业的人群中在筛选出符合性别条件的,此时范围已经比较小了,再利用姓名去排除
应该很快就能找到张三啦~
在上述例子的面向对象的思想中,我们是通过一类一类的去缩小范围去查找的,在面向对象编程中,类是一个很重要的概念。在Java中,
面向对象的本质: 以类的方式组织代码,以对象的方式组织封装数据。
从代码的层面分析,是先有类,再有对象,类是对象的模板,对象是类实例化之后的结果
从认识论层面分析: 应该是先有对象,再有类,类是在对象的基础上抽象出来的,就像是一群人,他们里面有一部分是老师,
一部分是学生,那么就可以将所有的老师归为一类,将所有的学生归为一类,剩余的人归为一类。
类有三大特性: 封装,继承,多态
类的方法
// 带有static标识符的是静态方法,是和类一起生成的
// 而不带有static称为是非静态方法,只有当类实例化后才会存在
// 所以在同一个类里,静态方法可以互相调用,而在静态方法直接调用非静态方法,必须重新实例化类
// 在非静态方法中可以调用非静态方法,不用重新实例化类
// 方法的重载: 名称相同,参数不同或者参数的类型不同
package createClass;
public class Method {
public static void main(String[] args) {
// test('aa'); 会报错
// 实例化之后再去调用就不会报错了
Method method = new Method();
method.test("test");
}
public void test(String name){
System.out.println(name); // test
test("aa","bb","cc"); // 3
int [] temp = {1,2,3,4};
test(temp); // 1,2,3,4
}
public void test(String ...name){
System.out.println(name.length);
}
public static void test(int[] arr){
for (int item:arr) {
System.out.println(item);
}
}
}
封装
封装是针对于类的属性,而与方法无关。利用private来实现内属性的私有,封装的目的是实现代码的高内聚,低耦合,通过对外部暴露一些接口或者方法实现对内部属性的操作。由于JS里面也有封装,理解这个概念在写一遍,熟悉下java的代码写法:
//封装一个student类,通过对外部暴露get/set方法,来操作内部属性,生成get/set时可以通过alt+ insert建来生成
package encapsulation;
public class Student {
// private: 标识符,标识属性私有
private String name;
private int age;
private char sex;
// 提供操作这些属性的方法,访问和操作
// 下文中的this指代的是当前的类
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
if(age > 120 || age< -1){
return;
}
this.age = age;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public char getSex() {
return sex;
}
}
引用如下:
//实例化一个student,通过get访问属性值,name的默认值为null,再通过set方法设置值以后,再调用get访问,他的值变为设置的值
//而再设置age的时候,由于再代码中加了判断,当age>120或者age< -1的时候,对内部的属性不去做任何操作,因此age的值依然时第一次调用age的值为3
```java
package encapsulation;
public class Demo {
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.getName()); // null
student.setName("梅子黄时雨");
System.out.println(student.getName()); // 梅子黄时雨
student.setAge(3);
System.out.println(student.getAge()); // 3
student.setAge(500);
System.out.println(student.getAge()); // 3
}
}
继承
继承的概念再js中也有,JS提供了比java更丰富的继承方式,通过原型、原型链、组合继承、寄生继承等方式,ES6中利用class和extends来实现继承的方式和java是挺像的。
继承的本质就是对一批类的抽象,对现有世界更好的建模。
继承表示的是类与类之间的一种关系,除此以外类和类的关系还有依赖、组合、聚合等。
继承关系的两个类,一个为子类(派生类),一个为父类(基类),子类继承父类使用关键字extends来表示。
所有的类都是Object类的子类。写一段代码熟悉一下新的继承写法吧
封装只和属性有关!封装只和属性有关!封装只和属性有关!
package extendsClass;
public class Demo {
public static void main(String[] args) {
Student student = new Student();
student.test();
}
}
// Person类
package extendsClass;
public class Person {
private String name;
private char sex;
private int age;
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
}
package extendsClass;
// student继承了person,会拥有person的属性和方法,如果person的属性是私有的,那么student将不能继承,就不能通过.的方式来访问了。
public class Student extends Person {
public void test(){
Student student = new Student();
//System.out.println(student.name); // 会报错,需要通过类暴露的方法和接口去访问和操作属性
System.out.println(student.getName()); // null
System.out.println(student.getAge()); // 0
student.setName("学生");
System.out.println(student.getName()); //学生
}
}
this,super和构造器
super调用父类的构造方法,必须在构造方法的第一行
super调用必须只能出现在子类的方法或者构造方法中
super和this不能同时调用构造方法
this本身指调用者这个对象,没有继承也可以使用,this默认调用本类的构造,而super指的是父类的构造
package extendsClass;
public class Person {
public Person() {
System.out.println("Person无参构造执行了");
}
protected String job ="person";
public void print(){
System.out.println("person");
}
}
package extendsClass;
public class Student extends Person {
private String job = "syudent";
// 先调用父类的无参构造,在调用子类的无参构造, super()
// 写了有参构造以后,无参构造必须显示定义
// 如果父类没有无参构造,那么子类也无法定义无参构造
public Student() {
// super(); 显示调用父类的构造,必须放在子类构造的第一行
System.out.println("Student无参构造执行了");
}
// 私有的属性无法被继承
public void test(String job){
System.out.println(job); //total
System.out.println(this.job); //student
System.out.println(super.job); //person
print(); //当前类的print方法 testAAa
this.print(); //当前类的print方法 testAAa
super.print();//父类的print方法 person
}
@Override
public void print() {
// super.print();
System.out.println("testAAa");
}
}
package extendsClass;
public class Demo {
public static void main(String[] args) {
Student student = new Student();
student.test("total");
}
}
多态
统一方法可以根据发送对象的不同而采用多种不同行为的方式。
一个对象的实际类型是确定的,但是指向对象的引用的类型有很多。
多态是方法的多态,属性是没有多态的
父类和子类有联系,如果没有会报类型转换异常 classCastExpection!
存在的条件:继承关系,存在方法重写,父类的引用指向子类的对象 Father f1 = new son()
方法重写: static方法不能被重写,不属于实例
final修饰的方法也不能被重写
private修饰的方法也不能重写
package moreInstance;
public class Person {
public void test(){
System.out.println("test");
}
}
package moreInstance;
public class Test {
public static void main(String[] args) {
// 一个对象的实际类型是确定的
// student调用的方法都是自身或者继承自Person的
Student student = new Student();
// 可以指向的引用类型就不是确定的了
// 父类的引用指向子类
// 对象能执行哪些方法主要看左边的类型和右边的关系不大
// student1不可以调用子类独有的方法
Person student1 = new Student();
//
Object student3 = new Student();
student1.test(); //StudentTest
student.test(); //StudentTest
student.eat();
// student2.eat(); 直接会报错
((Student)student3).eat(); //转为Student类
}
}