面向对象 + 一个项目应该只有一个main方法
补充
- final修饰的类不能被继承。给类加final修饰符是为了禁止其他类继承该类的方法。而其成员变量可以是final也可以不是final。
- 自动生成的getter/setter都是public,是为了其他类可以调用;static变量生成static的getter/setter,非static变量生成的没有static。从编译角度说,成员变量和getter/setter的static与非static不能交叉。
要把基础掌握扎实再往后面学,不要到这个地方基础都学得不扎实你还想着往后面学,这样就会欠得基础债越来越多,如果债欠得越来越多你到后面就学不动了,就想放弃,这也就是很多自学的人学到后面产生想放弃念头的原因了。
面向对象
面向对象编程的本质
Objective-Oriented Programming,OOP
面向对象编程的本质是:以类的方式组织代码,以对象的方式组织(封装)数据。
类用来组织对象,对象是类的实例,类是对象的模板。
对象是对客观事物的抽象,类是对对象的抽象。
类、对象的构成
再复杂的类、对象都是由属性和方法构成的。
静态方法和非静态方法
加了static的方法是静态方法,归属于类,调用只需要类名.方法名()。
不加static的方法不是静态方法,调用需要实例化出一个对象,再用对象名.方法名()。
静态方法和类一起加载,非静态方法是类实例化后才存在的。
值传递和引用传递
值传递:调用一个方法改变一个变量的值,出方法后会发现变量值没有被改变。
引用传递:本质上还是值传递,调用一个方法改变一个对象的一个成员变量的值,出方法后会发现变量值改变了。(否则setter就都不管用了)
使用new关键字本质是在调用构造器
String类型在底层是final char[]
封装
-
封装=属性私有+getter/setter
-
高内聚:类的内部数据操作细节自己完成,不允许外部干涉‘
-
低耦合:仅暴露少量的方法给外部使用
-
封装:数据隐藏,通常应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。(像是密码的加密解密?)
弹幕:是为了安数据“安全”,访问者写错了会没有权限,出错也方便修改bug(出错了方便修改bug是什么意思?答:get和set的逻辑都在getter、setter方法里)
封装的意义:
- 安全性:提高程序的安全性,保护数据,可以通过编辑getter方法选择是否允许获得数据、通过编辑setter方法避免不合法数据破坏系统
- 隐藏代码的实现细节(对用户)
- 统一接口,所有类都是get、set
- 提高系统的可维护性,便于修改
继承
extends扩展,子类是父类的扩展/子类继承父类
private的变量或方法不能继承,但是可以用getter/setter来访问private变量
-
子类会继承父类的static变量的值,除非再声明覆盖
-
子类会继承父类的getter和setter,对static变量来说改的是父类的变量,除非再声明覆盖
-
子类的static方法是归属于子类而不归属于其父类的,比如它和父类的static方法同名同参数类型列表时不用写@Override
-
子类的非static方法不能访问父类的static变量,也不能重写父类的static方法
-
子类的static方法不能重写父类的非static方法
super关键词可以调用父类的变量,super()是父类的构造器,子类构造器运行前会先运行父类构造器,重写构造器方法时super()得写在第一行,不写的话super()默认隐藏在第一行
类之间的关系还有依赖、组合、聚合等。
重写
public class A extends B{}
public class B{}
B b = new A()
-
对于静态方法而言:
b.方法名()调用方法时调用的是B类的方法而不是A类的方法。因为静态方法和类绑定,而不是new出来的,所以声明的时候就定了这个方法名对应哪一个方法
静态方法不存在重写,因为无法从static上下文引用非static字段或方法,属于类的静态方法也无法重写实例方法。两者都是static则两个方法各属于其所在类,没有重写关系。
-
对于非静态方法而言:(重写)
会看到IDEA左边显示"O"标志表示重写
@Override重写注解不写也行,和注释一样是给人看的
非静态方法可以在new的时候重写,之所以叫重写是因为”B b“声明的时候写入的是父类的方法,”new A()“创建对象的时候写入子类的方法覆盖原有方法。
注意:
-
重写的方法必须是public而不能是private,否则子类不能访问父类方法,也就不能"重写"了。
-
final方法也不能重写,final方法在常量池里。
-
重写:子类重写父类的方法
- 方法名必须相同
- 参数类型列表必须相同
- 权限范围可以扩大但不能缩小
- 抛出异常类可以缩小不能升级
为什么需要重写:
父类的功能子类不一定需要,也不一定满足子类的需求
快捷键:Alt+Insert Override
多态
多态是方法的多态,属性没有多态性。
多态指同一方法可以根据发送对象的不同而采取多种不同的行为方式。
一个对象的实际类型是确定的,但是可以指向这个类型的引用类型有很多。比如B b = new A()。
所以说,“同一方法……采取多种不同的行为方式”就是基于“指向这个类型的引用类型”是哪一个。
多态的好处在于可以实现动态编译,即引用类型可以在执行过程中决定,方便了大型系统的可扩展性。
(所以以前遇到过用Object声明的对象,而Object是祖宗类,这种用法包含在Father f = new Son();用法里)
instanceof关键字
// 某对象 instanceof 某类 语句结果是“该对象是该类的实例”这一命题的真假。
Son s = new Son();
System.out.println(s instanceof Father);//true
//Object->String
//Object->Person->Student
Object obj = new Student();
System.out.println(obj instanceof String);//false
System.out.println(obj instanceof Person);//true
Person p = new Student();
System.out.println(p instanceof Student);//true
System.out.println(p instanceof Object);//true
System.out.println(p instanceof String);//编译报错
声明类 对象名 = new 声明类的子类();
“声明类”是我起的名字,老师会称之为引用类型名。
要求instanceof左边对象的声明类和instanceof右边的类有直接血缘关系而不能是兄弟类关系等。
引用类型之间的转换
显式转换:
加括号可以将父类对象转为子类对象,从而可以调用子类的方法。
((Son)father).goToKindergarten();
隐式转换:
如果父类引用指向子类对象,相当于隐式地把子类对象转换为了父类对象,导致丢失了子类的方法。(用前面的语言解释,应该说成是方法用引用类型而不是对象类型区分命名空间,对象类型具有但引用类型不具有的方法就无法调用)
//引用类型名 对象名 = new 对象类型名();
Person person = new Student();
person.听课();//编译出错
类比:
基本类型的强制转换比如小数转为整数或double转为float会丢失精度,而其隐式转换比如声明double类型用int变量赋值不会丢失精度;
引用类型使父类引用指向子类对象可以认为是把子类对象隐式转换为父类对象而没有加括号,丢失的是子类有、父类没有的方法,由父类对象加括号强制转换为子类对象则使得可以调用原本不能调用的子类方法。
多态是为了方便方法调用,通过转换或申请(子类直接调到父类方法)可以调用其他类的方法,可以减少重复代码(类之间不同方法另写,相同方法可以共用),使代码更简洁。
封装、继承、多态是面向对象的三大特性,核心是抽象的编程思想。
以后在此基础上还有更抽象的“抽象类”,以及比抽象类更抽象的“接口”。
项目结构
一个项目应该只存在一个main方法,一般建一个Application类,把psvm写在里面作公共的测试类。