面向对象
面向对象是相对面向过程而言的。面向过程注重的是过程,强调的是动作;面向对象注重的是对象,只要找到了对应的对象,那么就自然拥有了对象所具有的一切功能
面向对象是基于面向过程的。
面向对象一定优于面向过程吗?当场景比较复杂的时候,建议使用面向对象;当事物比较简单的时候,建议使用面向过程
类和对象的关系
根据一类事物进行抽取,将这一类事物用一个类表示,同时将这一类事物的共有特征抽取成属性,将这一类事物的共有行为抽取成了方法---类是对象的抽取/概括
通过new关键字来产生对应的对象---对象是类的实例化/具体化
对象在内存中的存储
对象在传值的时候传递的是地址
成员变量和局部变量的区别
1. 定义位置不同:成员变量是定义在类内方法外;局部变量是定义在方法或者语句内部
2. 作用域不同:成员变量作用域整个类;局部变量只能在定义的方法或者语句内部使用
3. 内存存储位置不同:成员变量存在堆内存中,并且在堆内存中自动的赋予默认值;局部变量是存储在栈内存中,不会自动给值
4. 生命周期不同:成员变量是随着对象的创建而加载到堆内存中,随着对象的回收而释放;局部变量在方法或者语句执行的时候才会创建,随着方法或者语句的结束而立即移除出栈内存
构造方法
在类中与类同名而没有返回值类型的方法---主要是用于创建对象
构造方法可以重载
如果一个类没有手动提供构造函数,那么JVM在编译的时候会添加一个无参的构造方法。
构造方法没有返回值类型,也没有返回值,能写return语句吗?---可以---规避风险
this关键字
注意:在Java中所有的非静态属性和非静态方法都会通过对象来调用的。
this代表当前在使用的对象---可以认为是一个虚拟对象---可以通过this在本类中调用本类的方法和属性
this语句表示在本类的构造函数中调用本类的其他的对应形式的构造函数---必须放在构造函数的第一行
构造代码块
在类内方法外用{}定义的代码块---构造代码块/初始化代码块---在创建对象的时候先于构造函数执行---无论调用哪个构造函数都可以去执行某些必要的代码
局部代码块
在方法内或者语句内用{}定义的代码块---局部代码块---可以限制变量的使用范围和生命周期,主要是为了提高内存的利用率
int i = 0; while(i < 10); { System.out.println(i); i++; }
匿名对象
没有名字的对象---在创建之后只能使用一次---可以作为参数进行传递
面向对象的特征
封装、继承、多态 (抽象)
封装
体现形式:
1. 方法---提高了代码的复用性
2. 通过将属性私有化然后提供对外的公共的访问方法来设置该属性,可以在方法中对属性的设置或者获取做一系列的限定---属性的私有化---使属性值更符合要求---提高了代码的安全性
权限修饰符
用于限定变量或者方法的使用范围的
| 本类 | 子类 | 同包类 | 其他类 |
public | 可以 | 可以 | 可以 | 可以 |
protected | 可以 | 可以 | 可以 | 不可以 |
默认 | 可以 | 同包子类可以 | 可以 | 不可以 |
private | 可以 | 不可以 | 不可以 | 不可以 |
public的使用范围最大
继承
如果一些类中有一些共有的方法和属性,将这些方法和属性提取出来放到一个新的类中,然后利用extends关键字让原来的类和新的类产生联系---继承。新的类称之为父类(超类,基类),原来的类称之为子类(派生类)
在Java中支持的是单继承---一个子类只能有一个父类,而一个父类可以有多个子类
Java中支持多层继承
优点:提高了代码的复用性,使方法的调用更加安全
单继承和多继承的优劣性比较:
多继承在代码的复用性上要优于单继承
class A{ public int m(){ return 2; } } class B { public int m(){ return 1; } } public class C extends A, B{} C c = new C(); int i = c.m(); // 多继承会产生方法调用的混乱
可以提高代码的复用性,可以避免方法调用的混乱---提高了方法调用的安全性
super关键字
super表示在子类中代表了父类的对象---通过super来调用父类中的方法或者属性---可以将super看成一个虚拟对象
super语句---在子类构造函数中通过调用super语句来创建一个父类对象---如果父类中没有提供无参构造,那么这个时候子类的构造函数中手动添加一个super语句---super语句必须放在子类构造函数的首行
子类的构造函数中必然直接或者间接的有一个super语句---在创建子类对象的时候必然先创建一个父类对象
方法的重写
当父子类中产生了方法签名完全一致的方法的时候,构成了方法的重写/覆盖
注意:方法的重写需要遵循 “两等两小一大”
1. 方法签名必须一致
2.子类中重写的方法的权限修饰符要大于等于父类
class A { public void m(){} } class B extends A { void m(){} } A a = new B(); // 声明a对象的时候用的A类,那么A类告诉a对象可以使用一个m方法,并且告诉a对象这个m方法是一个public修饰的方法在任何地方都可使用 a.m(); // 具体的实现用的是B这个子类,当执行方法的时候需要看具体子类,发现这个方法使用默认权限修饰的
3. 如果父类方法的返回值类型是引用类型,那么子类重写的方法的返回值类型是父类方法返回值类型本身或者子类
class A { public void ma(){} } class B extends A { public void mb(){} } class C { public B m(){/*more code here*/} } class D extends C { public A m(){/*more code here*/} } C c = new D(); // 声明c对象用的是C类,C类告诉c对象有一个m方法可以使用,并且这个m的方法的返回值类型是一个B类型 B b = c.m(); // 方法的具体执行要看子类,子类中实际上这个方法的返回值类型是A---子类对象接了一个父类对象 b.mb(); // 子类接了一个父类对象,所以实际上是一个父类对象,而父类对象中不一定含有子类中独有的方法
4. 如果父类方法的返回值类型是基本类型/void/最终类的时候,子类的方法的返回值类型要一致----基本类型之间没有继承关系
5.子类抛出异常小于等于父类方法抛出异常
问题:能够用子类来接住一个父类对象么?---不行
B -> A
B b = new A();
多态
编译时多态:函数的重载
运行时多态: 向上造型---基于继承,重写---继承是运行时多态的前提
也可以分为:
行为多态:函数的重载和重写
对象多态:向上造型
注意:向上造型用父类声明用子类初始化---由于这个对象是父类声明的,所以对象能够干什么需要看父类;由于是用子类初始化,具体怎么干要看子类
static
修饰变量、方法、内部类、代码块
方法区
存储类信息。存储类的基本信息的区域称之为静态常量池。存储静态属性和静态方法的地方称之为静态区。
一个类在第一次真正使用的时候才会向方法区中加载---所以类只加载一次,加载完成之后就不再从方法区中移除。
静态变量
static修饰变量---静态变量,也叫类变量---随着类的加载而加载到了方法区中的静态区,并且在静态区中自动赋予了一个默认值。静态变量先于对象而存在,所以静态变量可以不通过对象而通过类来调用,也可以通过对象来调用。该类产生的所有的对象实际上存的是该静态变量在静态区中的地址,静态变量是被所有对象所共享的。
问题:静态变量能否定义到构造代码块中?---不可以
可以在构造代码块中对静态变量赋值么?---可以
静态方法
static修饰方法---静态方法,也叫类方法---在类加载的时候加载到了方法区中静态区,只是存储在静态区,在方法被调用的时候到栈内存中执行。静态方法先于对象而存在的,所以静态方法可以通过类名来调用,也可以通过对象来调用。
Arrays.sort()
Arrays.toString()
Arrays.copyOf()
System.arraycopy()
问题:可以在静态方法中定义静态变量吗?---不可以,因为静态方法是随着类的加载而加载到了方法区中的静态区,并不执行,而是在被调用的时候去栈内存中执行,所以无法定义静态变量
能在静态方法中直接调用本类中的非静态方法吗?---不可以
能在主函数中使用this或者super吗?---不可以
静态方法可以重载吗?---可以
静态方法可以重写吗?---不可以
父子类中可以存在方法签名一致的静态方法么?---可以---如果父子类中存在了方法签名完全一致的方法,要么都是静态的,要么都是非静态的。
注意:类只加载一次,是在第一次使用的时候才加载到方法区,而且加载到方法区中之后就不再移除了。
静态代码块
用static{}包括起来的代码
执行顺序:父类静态->子类静态->父类非静态->子类非静态
当父类与子类都有静态代码块和构造函数的时候,执行顺序如下:父类静态代码块 > 子类静态代码块 java虚拟机加载类时,就会执行该块代码。
父类构造函数 > 子类构造函数 (先有父亲,后有孩子)
如果是多级继承关系的话,高层的父类首先执行,然后依次递减。
总结:静态优先执行,父类优先于子类执行。 静态代码块是在JVM加载类的时候执行的,而且静态代码块执行且仅执行一次
final
修饰数据,方法以及类
当final修饰数据的时候,称之为常量---在定义好之后不可改变
final修饰方法---最终方法---不可以被重写,可以重载,可以被继承。
final修饰类---最终类---不可以被继承
静态方法可以用final修饰吗?--可以
子类在继承父类的时候,哪些东西是在子类中不可见的?---private,代码块,构造函数
抽象类
abstract
将一些名称一致但是细节不同的行为提取到父类中定义为抽象方法,抽象方法所在的类就是抽象类
抽象类不能用于创建对象,并且子类在继承抽象类的时候必须实现其中的抽象方法,或者把子类也定义为一个抽象类
如果所有的子类中存在了一些名称一致而细节不同的方法的时候,这个时候可以在父类中声明该行为,此时声明行为的时候不需要添加方法体,所以此时该方法就形成了抽象方法---abstract修饰---抽象方法所在的类一定是抽象类。
问题:
抽象类一定不能用于创建对象---有构造函数吗?---有
抽象类中可以有抽象方法也可以没有抽象方法。抽象类中可以定义一切的属性以及普通方法和静态方法。
抽象方法之间可以重载吗?---可以---重载只关心方法名和参数列表
抽象方法可以用static修饰吗?---不可以,因为static无法重写
抽象方法可以用final修饰吗?---不可以
抽象方法可以用private修饰吗?---不可以
如果一个抽象方法的权限修饰符是默认权限,对子类是否有要求?---要求子类必须同包
最终类可以是抽象类吗?---不可以---最终类不可以被继承
子类在继承父类的时候,什么东西无法继承?
构造方法、所有的私有的东西、代码块
接口
用interface来声明一个接口。---接口不能实例化。---类用implements来实现一个接口。类在实现接口之后需要实现接口中所有的抽象方法。
接口中的方法默认是抽象方法而且只能是抽象方法(JDK1.7及其以前)。
单继承,多实现---一个类只能继承一个父类,但是可以实现多个接口---一旦出现了多实现,那就必不可免的会导致方法的混乱---针对的是类
在Java中,允许接口之间进行多继承
接口中不允许定义构造方法---虽然接口在编译完成之后会产生class文件,但是接口不是类
Java中支持的是单继承,多实现---一个类只能继承一个类,但是一个类可以实现多个接口
注意:接口之间是多继承
问题:
接口有构造函数吗?---不可以
接口中能定义属性吗?---可以---接口中属性默认是一个静态常量
接口中的抽象方法可以是默认的权限修饰符吗?---不可以---接口中的方法默认是public修饰
可以用protected修饰接口中的方法吗?---不可以
接口中可以定义属性,默认是用public static final 来修饰
接口可以作为模板---反射
面试题:抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口么。
1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
2、抽象类要被子类继承,接口要被类实现。
3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现
4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
6、抽象方法只能申明,不能实现。abstract void abc();不能写成abstract void abc(){}。
7、抽象类里可以没有抽象方法
8、如果一个类里有抽象方法,那么这个类只能是抽象类
9、抽象方法要被实现,所以不能是静态的,也不能是私有的。
10、接口可继承接口,并可多继承接口,但类只能单根继承。
内部类
定义在类或者接口中的类就称之为内部类
封装的第三种形式
方法内部类
定义在方法中的类--只能定义它的方法中使用;方法内部类中不能定义静态属性和静态方法但是可以定义静态常量;方法内部类可以使用外部类中的一切属性和方法,但是如果使用当前方法的数据的时候,要求这个数据是一个常量
方法内部类先于方法加载
当方法内部类使用当前方法中的局部数据时,要求这个数据是一个常量;
在1.8中i可以不用显示声明为一个常量,但本质上还是一个常量
成员内部类
定义在类内方法外的类
可以定义静态常量、利用外部类对象来创建内部类对象,不能定义静态方法和静态属性,可以定义普通方法和属性
使用外部类中的一切方法和属性
可以用权限修饰符修饰内部类
静态内部类
用static修饰的内部类
可以定义一切的属性和方法
静态内部类只能使用外部类中的静态属性和静态方法
匿名内部类
匿名内部类本质上是继承了对应的类或者是实现了对应的接口---只要一个类可以被继承,那么这个类就可以出现匿名内部类的形式。
如果匿名内部类定义到了方法中,此时匿名内部类的使用规则和方法内部类一致
如果匿名内部类定义到了类中,此时匿名内部类的使用规则和成员内部类一致、
扩展:内部接口---定义在类或者接口中的接口---类中定义的接口、接口中定义的类或者是接口默认都是用static修饰
包
声明包用的package---一个Java文件中只允许存在一个package语句,而且这个package语句必须放在整个Java文件的首行
导入包用的是import,
import java.util.*---表示导入util包下的所有的类而不包括子包下的类--- *是一个通配符
java.lang---核心包---在程序启动的时候就已经加载到了方法区中了---在使用的时候不需要导包
java.util---工具包---存放了一系列简化操作的工具类
java.io---数据传输
java.net---网络传输
java.math---数学运算
java.sql---数据库
java.awt---图形用户界面---几乎不用
java.security---数据安全
java.text---格式化
javax.*---扩展包
org.*---第三方厂商和开源社区提供的包
注意:包名不能以java,javax,org开头