面向对象基础
面向对象和面向过程的区别
面向过程:关注的执行过程,重在参与。
面向对象:关注的是功能的一个对象,执行者到指挥者的转变。
面向对象比较抽象,难以理解。
从更高的层次来进行对象的创建,更能贴近事物的一个本质。
面向对象的三大特征
封装:把一些实现的细节封装起来
继承:多个类把相同属性和行为形成一个总类,其他类用总类的属性和行为
多态:一种事物的多种形态。方法的重写
面向对象思想:
OOA:面向对象分析(Object Oriented Analysis)
OOD:面向对象设计(Object Oriented Design)
OOP:面向对象程序(Object Oriented Programming
方法定义格式
权限修饰符 返回值类型 方法名(形式参数列表){
//方法体
return 返回值;
}
栈、堆、方法区储存对象区别
栈存储的是:基本数据类型的数据 以及 引用数据类型的引用
堆存放的是:类的对象
方法区存放的是:类信息、 静态的变量 、常量、成员方法
构造函数
命名方法
方法名称必须与类名相同, 没有返回值类型的声明
作用
- 初始化对象
- 给类中的属性初始化
特点
- 所有的java类中至少有一个构造方法
- 如果类中没有写明构造方法,就会生成一个无参的构造方法
- 方法名和类名相同,没有返回值类型
方法重载
特点:方法名相同,参数类型或参数长度或参数顺序不同,能否重载与与返回值无关
在不同的需求下,传递不同的参数调用方法完成具体功能
匿名对象
没有对象名称的对象 就是匿名对象
匿名对象只能使用一次,因为没有任何的对象引用,所以将称为垃圾,等待被GC回收
面向对象进阶
封装 private
为了避免值设置的逻辑错误,类中的属性都应设置为private,并提供setter和getter接口
this的作用
- 调用类中的属性
- 调用类中的方法或构造方法
- 表示当前对象
this() :调用当前类中的构造方法
this(参数):有几个参数就调用当前几个参数的构造方法
this()必须放在构造方法的第一行上
static
- 静态成员 在类加载时加载并初始化。
- 无论一个类存在多少个对象 , 静态的属性, 永远在内存中只有一份( 可以理解为所有对象公用 )
- 在访问时: 静态不能访问非静态 , 非静态可以访问静态
代码块
普通代码块
在执行的流程中出现的代码块 {}, 我们称其为普通代码块
构造代码块
在类中的成员代码块{}, 我们称其为构造代码块, 在每次对象创建时执行, 执行在构造方法之前
静态代码块
在类中使用static修饰的成员代码块 static{}, 我们称其为静态代码块, 在类加载时执行。 每次程序启动到关闭 ,只会执行一次的代码块
同步代码块
解决程序中不符合现实的规律(线程相关)
构造方法 与 构造代码块 以及 静态代码块的执行顺序
静态代码块 --> 构造代码块 --> 构造方法
权限修饰符
面向对象高级
继承
格式
class 类名 extends 类名1{}
规范
- 继承一个父类:单继承
- 继承父类所有属性行为
- 可以多重继承
- 除了继承父类属性和行为,还可以拓展自己的
super
前提条件
在继承关系中
使用方法
super.属性名:调用父类属性
super():调用父类无参的构造方法
子类如果没有写构造方法,Java默认提供无参的构造方法
提供一个默认的super()调用父类无参的构造方法
super(参数):父类有参数的构造方法
位置:放在子类构造方法第一行
重写
前提条件
继承关系
规则
- 参数列表相同
- 返回类型相同
- 访问权限不能比父类更低
override和overload的区别
- 发生的位置: 一个类中/子父类中
- 参数列表限制:必须不同/必须相同
- 返回值类型:与返回值类型无关/返回值类型必须一致
- 访问权限:与访问权限无关/子方法权限不能小于父
- 异常处理:与异常无关/异常范围要更小
抽象类
一个抽象类中可以没有抽象方法。抽象方法必须写在抽象类或者接口中。
格式:
abstract class 类名{ // 抽象类
}
原则
抽象类本身是不能直接进行实例化操作的,即:不能直接使用关键字new完成。
一个抽象类必须被子类所继承,被继承的子类(如果不是抽象类)则必须覆写(重写)抽象类中的全部抽象方法。
抽象类必须有子类才有意义,所以不能用==final==修饰;抽象类可以有构造方法,只是不能人为new出来,类中实现的部分实际上是封装起来
调用时都是要先调用父类中的构造方法(默认是无参的),之后再调用子类自己的构造方法)
抽象方法
只声明而未实现的方法称为抽象方法(未实现指的是:没有“{}”方法体),抽象方法必须使用abstract关键字声明
格式
abstract class 类名{ // 抽象类
public abstract void 方法名() ; // 抽象方法,只声明而未实现
}
抽象类和普通类区别
-
抽象类必须用public或protected修饰(如果为private修饰,那么子类则无法继承,也就无法实现其抽象方法)。 默认缺省为 public
-
抽象类不可以使用new关键字创建对象, 但是在子类创建对象时, 抽象父类也会被JVM实例化。
-
如果一个子类继承抽象类,那么必须实现其所有的抽象方法。如果有未实现的抽象方法,那么子类也必须定义为 abstract类
接口
如果一个类中的全部方法都是抽象方法,全部属性都是全局常量,那么此时就可以将这个类定义成一个接口。
定义格式:
interface 接口名称{
全局常量 ;
抽象方法 ;
}
接口中:只能使用全局常量,定义时可以省略public static final
抽象方法:定义时可以省略 public abstract
面向接口编程优点
- 降低程序的耦合性
- 易于程序的扩展
- 有利于程序的维护
接口的实现
格式
class 子类 implements 父接口1,父接口2...{
}
接口的继承
接口因为都是抽象部分, 不存在具体的实现, 所以允许多继承,例如:
interface C extends A,B{
}
注意:如果一个接口要想使用,必须依靠子类。 子类(如果不是抽象类的话)要实现接口中的所有抽象方法
接口和抽象类的区别
- 抽象类要被子类继承,接口要被类实现。
- 接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法。
- 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
- 抽象类使用继承来使用, 无法多继承。 接口使用实现来使用, 可以多实现
- 抽象类中可以包含static方法 ,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明静态方法)
- 接口不能有构造方法,但是抽象类可以有
多态
概念
对象的多种表现形式
重载: 一个类中方法的多态性体现
重写: 子父类中方法的多态性体现
多态的使用
对象的类型转换
向上转型:将子类实例变为父类实例
父类 父类对象 = 子类实例
向下转型:将父类实例变为子类实例
子类 子类对象 = (子类)父类实例
final
使用方法
-
修饰变量
-
修饰方法
不能被重写
-
修饰类
不能被继承
instanceof
作用
判断某个对象是否是指定类的实例,则可以使用instanceof关键字
格式
实例化对象 instanceof 类 //此操作返回boolean类型的数据
Object类
toString
建议重写Object中的toString方法。 此方法的作用:返回对象的字符串表示形式。 Object的toString方法, 返回对象的内存地址
equals
建议重写Object中的equals(Object obj)方法,此方法的作用:指示某个其他对象是否“等于”此对象。
实现了对象上最具区别的可能等价关系; 也就是说,对于任何非空引用值x和y ,当且仅当x和y引用同一对象( x == y具有值true )时,此方法返回true
内部类
广泛意义上的内部类一般来说包括这四种:
1、成员内部类 2、局部内部类 3、匿名内部类 4、静态内部类
成员内部类
class Outer {
private double x = 0;
public Outer(double x) { this.x = x;
}
class Inner { //内部类 public void say() {
System.out.println("x="+x); }
}
}
特点:
成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问 的是成员内部类的成员。
如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法
外部使用成员内部类 :
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner();
局部内部类
class Person{
public Person() {
class Man{
public Man(){
}
public People getPerson(){
class Student extends People{
int age =0; }
return new Student();
}
}
注意:局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。
匿名内部类
new 父类构造器(参数列表)|实现接口()
{
//匿名内部类的类体部分
}
使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。当然这个引用是隐式的。
注意:
- 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或 者实现一个接口。
- 匿名内部类中是不能定义构造函数的。
- 匿名内部类中不能存在任何的静态成员变量和静态方法。
- 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
- 只能访问final型的局部变量
静态内部类
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner(); }
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
} }
}
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。 静态内部类是不需要依赖于外部类对象的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员 变量或者方法
包装类
装箱:
基本数据类型转换成包装类
new integer(23)
拆箱:
包装类转换成基本数据类型
Double.doubleValue()
分类
- Number:Integer、Short、Long、Double、Float、Byte都是Number的子类表示是一个数字。
- Object:Character、Boolean都是Object的直接子类。
字符串转换
使用包装类还有一个很优秀的地方在于:可以将一个字符串变为指定的基本数据类型,此点一般在接收输入数据上使用 较多。
在Integer类中提供了以下的操作方法:
public static int parseInt(String s) :将String变为int型数据
在Float类中提供了以下的操作方法:
public static float parseFloat(String s) :将String变为Float
在Boolean 类中提供了以下操作方法:
public static boolean parseBoolean(String s) :将String变为boolean
可变参数
一个方法中定义完了参数,则在调用的时候必须传入与其一一对应的参数,但是在JDK 1.5之后提供了新的功能,可以根 据需要自动传入任意个数的参数。
语法:
返回值类型 方法名称(数据类型...参数名称){
//参数在方法内部 , 以数组的形式来接收
}
注意:
可变参数只能出现在参数列表的最后。
异常处理
运行错误分为error和exception,我们处理的是exception,exception分为checkedexception可查异常和uncheckedexception不可查异常。 checkedexception是编译异常,uncheckedexception是RuntimeException运行时异常,存在不会出现下红线。
异常捕获写法
try{
// 有可能发生异常的代码段
}catch(异常类型1 对象名1){
// 异常的处理操作
}catch(异常类型2 对象名2){
// 异常的处理操作 } ...
finally{
// 异常的统一出口
}
特殊的多异常捕获写法
catch(异常类型1 |异常类型2 对象名){ //表示此块用于处理异常类型1 和 异常类型2 的异常信息 }
try+catch的处理流程
- 一旦产生异常,则系统会自动产生一个异常类的实例化对象。
- 那么,此时如果异常发生在try语句,则会自动找到匹配的catch语句执行,如果没有在try语句中,则会将异 常抛出.
- 所有的catch根据方法的参数匹配异常类的实例化对象,如果匹配成功,则表示由此catch进行处理。
throws关键字
格式
返回值 方法名称()throws Exception{
}
自定义异常类
编写一个类, 继承Exception,并重写一参构造方法 即可完成自定义受检异常类型。
编写一个类, 继承RuntimeExcepion,并重写一参构造方法 即可完成自定义运行时异常类型。
class MyException extends Exception{ // 继承Exception,表示一个自定义异常类
public MyException(String msg){
super(msg) ; // 调用Exception中有一个参数的构造
} };
自定义异常可以做很多事情, 例如:
class MyException extends Exception{
public MyException(String msg){
super(msg) ;
//在这里给维护人员发短信或邮件, 告知程序出现了BUG。 }
};
异常处理常见面试题
-
try-catch-finally 中哪个部分可以省略?
答: catch和finally可以省略其中一个 , catch和finally不能同时省略
注意:格式上允许省略catch块, 但是发生异常时就不会捕获异常了,我们在开发中也不会这样去写代码. -
try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
答:finally中的代码会执行.
执行流程:
- 先计算返回值, 并将返回值存储起来, 等待返回
- 执行finally代码块 将之前存储的返回值, 返回出去;
需注意:
返回值是在finally运算之前就确定了,并且缓存了,不管finally对该值做任何的改变,返回的值都不会改变
finally代码中不建议包含return,因为程序会在上述的流程中提前退出,也就是说返回的值不是try或 catch中的值
如果在try或catch中停止了JVM,则finally不会执行.例如停电- -, 或通过如下代码退出 :
JVM:System.exit(0);