知识要点-面向对象
三大特征:封装,继承和多态
1.定义类语法
[修饰符] class 类名{
零到多个构造器定义..
零到多个成员变量..
零到多个方法..
}
- 修饰符可以是public,final,abstract或者完全省略,类名满足驼峰命名法
- static修饰的成员不能访问没有static修饰的成员
2.定义成员变量
[修饰符] 类型 成员变量名 [ = 默认值]
- 修饰符可以省略,也可以是public,protected,private,static,final
- 其中public,protected,private只能出现其一,可以与static,final组合使用
3.定义方法
[修饰符] 方法返回值类型 方法名[形参列表]{
//由零条到多条可执行性语句组成的方法体
}
- 修饰符可以省略,也可以是public,protected,private,static,final,abstract
- 其中public,protected,private只能出现其一,abstract与final只能出现其一,可以与static组合使用
- 无返回值,类型用void
4.static关键字
- static修饰的成员表明它属于这个类本身,而不属于该类的单个实例
5.定义构造器
[修饰符] 构造器名(形参列表){
//由零到多条可执行性语句组成的构造器执行体
}
- 修饰符可以省略,也可以是public,protected,private其中之一
6.this关键字
- Java允许对象的一个成员直接调用另一个成员,可以省略this前缀(js不行)
- static修饰的方法不能使用this引用,this无法指向合适的对象
- 方法内若有局部变量和成员变量同名,则必须使用this关键字
- 如果需要在静态方法中访问另一个普通方法,则只能重新创建一个对象
public class StaticAccessNonStatic{
public void info(){
System.out.println("简单info方法");
}
public static void main(String[] args){
//main()是静态方法,info()非静态
//下面语句会报错
info();
//可以修改为
new StaticAccessNonStatic().info();
}
}
7.方法
- Java中方法不能独立存在,要么属于类,要么属于对象
- 永远不能被独立执行,执行方法必须使用类或者对象作为调用者
8.形参
- 执行方法传入参数,参数为基本数据类型时,传入参数的变量被复制一遍,在方法内的变化并不会使外部的变量也发生变化
public class PrimtiveTransferTest{
public static void swap(int a,int b){
int temp = a;
a = b;
b = temp;
}
public static void main(String[] args){
int a = 1;
int b = 2;
//传入a和b并不会使a和b值发生改变,传入后值被复制
swap(a,b);
}
}
- 参数为引用类型时,传入参数被复制的仅仅是引用的变量,在方法内的变化会影响到引用的值(即堆内存中的值)也发生变化
class DataWrap{
int a;
int b;
}
public class ReferenceTransferTest{
public static void swap(DataWrap dw){
int temp = dw.a;
dw.a = dw.b;
dw.b = temp;
}
public static void main(String[] args){
DataWrap dw = new DataWrap();
dw.a = 1;
dw.b = 2;
//调用swap方法后,dw对象成员变量值会随之改变
swap(dw);
}
}
- 形参可以定义数量不确定形参,在最后一个形参类型后增加三点'...'
public static void test(int a,String... books){}
8.方法重载:同一个类中包含两个或以上方法名相同,形参不同(js没有,因为有可变参数,可以用算法实现)
- 不能用返回值类型作为方法重载判断方法,因为直接调用方法时,java无法判断使用哪种返回值类型
9.作用域
- Java作用域类似于JavaScript,但是Java存在代码块局部变量,即在代码块中定义的变量在外部无法访问(类似ES6中let)
10.成员变量初始化和内存中运行机制
class Person{
static int eyeNum;
String name;
}
//创建第一个Person对象
//第一次使用Person类,系统在第一次使用时加载这个类并进行初始化,为类变量eyeNum分配内存空间,指定默认初始值0
Person p1;
//Person类初始化完成后,系统在堆内存中分配一块内存区,创建一个实例对象,同时分配实例变量的内存空间,赋予初始值
//实例对象也包含类变量内存,并把对象赋给p1
p1 = new Person();
//创建第二个Person对象,不需要初始化Person类
Person p2 = new Person();
11.封装(Encapsulation)
-
使用访问控制符:private,protected,public
- private (当前类访问权限):如果类里的一个成员(成员变量,方法,构造器)使用private修饰,则这个成员只能在当前类的内部被访问。
适合于修饰成员变量 - default(包访问权限):如果类里的一个成员不使用任何修饰符,则它有包访问权限,可以被相同包下的其他类访问
-
protected(子类访问权限):如果类里的一个成员使用protected修饰,则这个成员既可以被同一个包中的其他类访问,也可以被不同包中的子类访问
使用protected来修饰一个方法,通常是希望其子类来重写这个方法
-public(公共访问权限):使用public修饰,则这个成员或外部类可以被所有类访问,不管访问类与被访问类是否在同一个包中,是否具有父子继承关系
- 如果java源文件中定义的所有类都没有使用public修饰,则这个java源文件的文件名可以是一切合法的文件名,但是如果一个java源文件里定义了一个public修饰的类,则这个源文件的文件名必须与public修饰的类的类名相同
//良好封装的Person类
public class Person{
//private修饰成员变量
private String name;
private int age;
//提供方法操作name成员变量
public void setName(String name){
if(name.length() > 6 || name.length() < 2){
System.out.println("不符合要求");
return;
}else{
this.name = name;
}
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
}
12.访问控制符基本规则
- 类里绝大部分成员变量都应该使用private修饰,只有一些static修饰的,类似全局变量的成员变量,才可能考虑使用public修饰。除此之外,有些方法只用于辅助实现该类的其他方法,这些方法称为工具方法,工具方法也应该使用private修饰
- 如果某个类主要用作其他类的父类,该类里包含的大部分方法可能仅希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰这些方法
- 希望暴露出来给其他类自由调用的方法应该使用public修饰。因此,类的构造器通过使用public修饰,从未允许在其他地方创建该类的实例。因为外部类通常都希望被其他类自由使用,所以大部分外部类都使用public修饰
13.package,import和import static
- 把一个类放在指定的包结构下,则在Java源程序的第一个非注释行放置
package packageName;
意味着该源文件里所有类都属于这个包 -
javac -d . HelloWorld.java
编译时,'-d'会自动建立对应的文件结构来放置class文件 - 父级包中的类调用子级包中的类时,必须有完整包路径加类名
- import语句出现在package之后,class定义之前,可以有多个import
-
import lee.sub.*
表示导入sub包下的所有类,不包括子包lee.sub.pic
- Java默认为所有源文件导入
java.lang
包下所有类,因此使用String
,System
都无需导入,但例如Arrays
类,位于java.util
包下 - 有重复类位于两个包时,应该使用全名,避免import
- import static导入静态成员变量,静态成员方法
import static package.subpackage.ClassName.fieldName | methodName
14.Java常用包
15.构造器(创建对象时执行初始化)
- 同一个类允许有多个构造器,根据形参不同,即构造器重载
16.类的继承
- 通过
extends
继承class children extends parents
- Java是单继承,Java类只有一个直接父类
- 未指定直接父类时,默认扩展
java.lang.Object
类,即java.lang.Object
是所有类的父类
17.类的方法重写(方法覆盖)
- 子类包含父类同名方法
- “两同两小一大”原则,方法名形参列表相同,子类方法返回值类型应比父类更小或相等,子类方法抛出的异常类应比父类更小或相等,子类方法的访问权限应比父类更大或相等
- 覆盖方法与被覆盖方法必须是同一种类,即类方法或实例方法
18.重载与重写
- 重载发生在同一个类多个同名方法之间,重写发生在子类和父类同名方法之间
19.super限定
-
super.method();
调用被重写的父类方法 - super不能出现在static修饰的方法中
- super可以访问到父类中因为同名被隐藏的实例变量
- super可以调用父类构造器中的初始化代码
20.继承树:创建Class B对象,系统先执行java.lang.Object
类的构造器,再执行Class A的构造器,然后才执行Class B的构造器
21.多态:引用变量编译时类型和运行时类型,编译时类型与运行时类型不一样,就可能出现多态
class BaseClass{
public int book = 6;
public void base(){
System.out.println("BaseClass");
}
}
class SubClass extends BaseClass{
public String book = "多态";
public void sub(){
System.out.println("sub方法");
}
public void base(){
System.out.println("SubClass");;
}
public static void main(String[] args){
//下面编译时类型和运行时类型一致,不存在多态
BaseClass bc = new BaseClass();
bc.book == 6;//true
SubClass sc = new SubClass();
sc,book == "多态";//true
//下面编译时类型为BaseClass,运行时类型为SubClass,存在多态
BaseClass ploymophicBc = new SubClass();
ploymophicBc.book == 6;//true,表明访问的是父类的实例变量
//ploymophicBc.sub()报错,编译时出现错误
}
}
- 子类是一种特殊的父类,Java允许把子类对象直接赋给一个父类引用变量,无需任何类型转换,称为向上转型,由系统自动完成
- 当把一个子类对象赋给一个父类引用变量时,运行时调用该引用变量的方法时,其方法行为总是表现出子类的行为特征,而不是父类的行为特征。出现相同类型的变量,调用同一个方法时呈现出多种不同的行为特征,这就是多态
- 对象的实例变量是不具备多态性的,引用变量在编译阶段只能调用其编译时所具有的方法
22.引用变量的强制类型转换
- 引用变量在编写时只能调用它编译时的类型的方法,而不能调用它运行时类型的方法,如果需要让这个引用变量调用它运行时类型的方法,则必须把它强制类型转化成运行时类型,借助于类型转换运算符
-
(type)variable
这种用法可以将variable变量转换成一个type类型的变量,也可以将一个引用类型变量转换成其子类类型,需注意:
基本类型之间的转换只能在数值类型之间进行
引用类型之间的转换只能在具有继承关系的两个类型之间进行,父类实例转换成子类类型,则必须这个对象编译时是父类类型,运行时是子类类型 -
instanceof
判断是否可以转换
23.instanceof
-
[引用类型变量] instanceof [类]
用于判断前面的对象是否是后面的类或者其子类,实现类的实例 - instanceof前面操作数的编译时类型要么与后面的类相同,要么与后面的类具有父子继承关系
24.继承使用原则
- 尽量隐藏父类的内部数据,尽量把父类的所有成员变量都设置成private访问类型,不要让子类直接访问父类的成员变量
- 不要让子类可以随意访问,修改父类的方法。父类中的辅助工具方法应该用private修饰
- 尽量不要再父类构造器中调用将要被子类重写的方法
25.初始化块
[修饰符]{
//代码
}
- Java类里可出现的第四种成员,可存在多个,在构造器运行之前运行
-
修饰符只能是static,静态初始化块,只在类初始化的时候执行