二、面向对象
1、面试对象思想:
(1)概述:面向对象对相对于面向过程而言的,面向过程强调的是功能,面向对象强调的是讲功能封装进对象,强调具备功能的对象;
(2) 思想特点:
- 是符合人们思考习惯的一种思想
- 将复杂的事情简单化
- 将程序员从执行者编程了指挥者
(3)特征:
封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式。
继承:多个类中存在相同的属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只需要继承那个类即可。
多态:一个对象在程序不同运行时刻代表的多种状态,父类或者接口的引用指向子类对象。
2、类和对象:
类:对现实世界中某种事物的描述,是抽象的。
对象:事物具体存在的个体。
3、成员变量和局部变量的区别(重点)
(1)作用域
成员变量:针对整个类有效。
局部变量:只在某个范围内有效(一般指的是方法,语句体内)。
(2)存储位置
成员变量:随着对象的创建而存在,随着对象的消失而消失。
局部变量:在方法被调用或语句被执行的时候存在,存储在栈内存中,当方法调用完或语句结束后,就自动释放。
(3)初始值
成员变量:有默认初始值。
局部变量:没有默认初始值,使用前必须赋值。
4、匿名对象
(1)匿名对象就是没有名字的对象,是对象的一种简写形式。
(2)应用场景
- 只调用一次类中的方法。
- 可以作为实际参数在方法传递中使用。
5、封装
定义:隐藏对象属性和实现细节,仅对外提供公共的访问方式;
优点:
- 将变化隔离
- 方便使用
- 提高复用性
- 提高安全性
6、private关键字在代码中的体现
- 私有的意思,代表权限修饰符
- 用来修饰成员变量和函数
- 用private修饰的成员只在本类中有效
- 私有是封装的一种体现
7、构造方法
(1)特点
- 方法名与类名相同
- 没有返回值类型
- 没有返回值
(2)作用
构造函数是用于创建对象,并对其进行初始化赋值,对象一建立就自动调用相对应的构造函数。
(3)构造方法的注意事项
- 如果一个自定义的类没有构造方法,系统会默认给出一个无惨构造方法。
- 如果一个自定义类提供了构造方法,那么系统将不再给出无参构造方法,这个时候你可以不适用无参构造方法,如果想适用,那么久必须手动给出无参构造方法。
*一般情况下,我们的自定义类都要手动给出无参构造方法。
(4)构造方法和成员方法的区别
A:格式区别
构造方法和类名相同,并且没有返回值类型,也没有返回值。
普通成员方法名可以任意起,但不能和系统重名,必须有返回值类型,可以没有返回值。
B:作用区别
构造方法用于创建对象,并进行初始化值。
普通成员方法用于完成特定的功能。
C:调用区别
构造方法的在创建对象时被调用的,一个对象建立,只调用一次相应的构造函数。
普通成员方法是由创建好的对象调用,可以调用多次。
8、构造代码块
(1)作用:
给对象进行初始化,对象一建立就执行,而且优先于构造函数执行。
(2)构造代码块和构造函数的区别:
- 构造代码块是给所有不同对象的共性进行统一初始化
- 构造函数是给对应的对象进行初始化
9、this关键字
(1)this关键字代表本类对象的一个引用,谁调用的this所在的方法,this就代表谁
(2)this的使用场景
- 用于区别成员变量和局部变量;
- 在定义函数时,该函数内部要用到调用函数的对象时,因为此时对象还没有建立,故用this代表次对象。
- 构造函数间调用
this参数必须作为第一条语句存在。
10、Person p = new Person();在内存中做了哪些事情。
- 将Person.class文件加载进内存中。
- 如果P定义在主方法中,那么久会在栈空间开辟一个变量空间p。
- 在堆内存给对象分配空间。
- 对对象中的成员进行默认初始化。
- 对对象中的成员进行显示初始化。
- 调用构造代码块对对象进行初始化(如果没有就不执行)。
- 调用构造方法对对象进行初始化,对变量初始化完毕。
- 将对象的内存地址赋值给p变量,让p变量指向该对象。
11、static关键字
(1)静态的意思,用来修饰成员变量和成员函数。
(2)静态的特点
- 随着类的加载而加载
- 优先于对象存在
- 对所有对象共享
- 可以被类名之间调用
(3)静态的注意事项
A:静态方法只能访问静态成员,因为静态的内容是随着类的加载而加载的,它先进内存。
B:静态方法中不能使用this、super关键字。
C:主方法是静态的
public static void main (String []args)
public : 公共的意思,是最大的权限修饰符。
static : 由于jvm调用main方法的时候,没有创建对象,只能通过类名调用,所以main必须是static修饰。
void : 由于main方法被jvm调用,不需要返回值,用void修饰。
main : main是主要的意思,所以jvm采用这个名字,它是程序的入口。
String[] : 字符串数组
args : 数组名
在运行的时候,通过java命令给args数组赋值。
(4)静态变量和成员变量的区别
A:调用方式
- 静态变量也成为类变量,可以直接通过类名调用。也可以通过对象名调用,这个属于类。
- 成员变量也成为实例变量,只能用过你对象名调用,这个属于对象。
B:存储位置
- 静态变量存储在方法区长中静态区。
- 成员变量存储在堆内存中。
C:生命周期
- 静态变量随着类的加载而存在,随着类的消失而消失,生命周期长。
- 成员变量随着对象的创建而存在,随着对象的消失而消失。
D:与对象的相关性
- 静态变量的所有对象的共享的数据。
- 成员变量是每个对象所特有的数据。
(6)什么时候使用静态?
- 当所有对象共享某个数据的时候,就把这个成员变量定义为静态修饰。
- 当某个方法中没有访问该类中的非静态成员,就可以把这个方法定义为静态修饰。
- 静态的生命周期较长,所以一般不推荐使用。
(7)静态代码块
- 它只执行一次,它比main方法还先执行。
- 执行顺序 静态代码块 → 构造代码块 → 构造方法
12、制作API(次重点)
API(全拼):Application Program Interface 应用程序编程接口。
(1)类中的内容需要用文档注释。
(2)使用JDK\bin目录下的javadoc工具。
格式:javadoc -d 目录 -author -version ArrayTool.java
13、单例设计模式
(1)设计模式是什么?
解决某类问题行之有效的方法,是一种思想,是规律的总结。
(2)用来保证某个类的内存中只有一个对象。
(3)保证唯一性的思维及步骤
- 为了避免其他程序简历该类对象,先禁止其他程序简历该类对象,即将构造函数私有化。
- 为了其他程序访问到该类对象,需在本类中创建一个该类的私有对象。
- 为了方便其他程序访问到该类对象,可以提供对外公共的访问方式。
(4)单例设计模式的两种方式
A:饿汉式 当类加载的时候,就创建对象。
class Student
{
private Student(){}
private static final Student s = new Student();
public static Student getInstance()
{
return s;
}
}
B: 懒汉式 当使用的时候,才去创建对象。
class Student
{
private Student(){}
private static final Student s = null;
public static Student getInstance()
{
if(s==null)
{
//线程1就进来了,线程2就进来了。
s = new Student();
}
return s;
}
}
懒汉式和饿汉式的区别
- 饿汉式是类一加载进内存就创建好了对象。
- 懒汉式则是类加载进内存的时候,对象还没有存在,只有调用getInstance() 方法时,对象才开始创建。
- 懒汉式是延迟加载,如果多个线程同时操作懒汉式时就可能出现线程安全问题,解决线程安全问题可以加同步来解决。但是加了同步之后,每次都比较繁琐,效率变慢,所以加双重锁来提高程序效率。
- 开发常用饿汉式,因为饿汉式简单安全。懒汉式容易发生问题。
14、Math类的使用(重点)
(1)数学操作类 : 该类没有构造方法,方法均为静态。
(2)掌握内容
A :成员变量:
E:比任何其他值都更接近e(即自然对数的底数)的double值。
PI:比任何其他值都更接近pi(即圆的周长与直径之比)的double值。
B:成员方法
static double abs(double a)
返回 double 值的绝对值。返回绝对值
static double ceil(double a)
返回最小的(最接近负无穷大)double 值,该值大于等于参数,并等于某个整数。
static double floor(double a)
返回最大的(最接近正无穷大)double 值,该值小于等于参数,并等于某个整数。
max:返回两个值中较大的那个
min:返回两个值中较小的那个
static long round(double a)
返回最接近参数的 long。
static int round(float a)
返回最接近参数的 int。
static double random()
返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。
static double pow(double a, double b)
返回第一个参数的第二个参数次幂的值。
static double sqrt(double a)
返回正确舍入的 double 值的正平方根。
15、Random类的使用(重点)
(1) 产生一个随机数的类
(2) 掌握内容
- 构造方法
Random(); 创建一个新的随机数生成器.
Random(long seed); 使用单个long种子创建一个新的随机数生成器. - 成员方法
int nextlnt(); 返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的int值.
int nextllnt(int n); 返回一个伪随机数,它是取自此随机数生成器序列的,在0(包括)和指定值(不包括)之间均匀分布的int值.
16、Scanner类的使用
(1)可以获取从键盘输入的数据
(2)掌握内容
- 构造方法
Scanner(ImputStream source) 构造一个新的Scanner,它生成的值是从指定的输入流扫描的。
如:Scanner sc = newScanner(System.in);
方法摘要: - sc.nextInt();
- sc.nextLine();
17、继承(重点)
(1)继承的概念把很多类的相同特征和行为进行抽取,用一个类来描述。让多个类和这个类产生一个关系。
好处:多个类可以省去很多代码,这个就是继承关系。
(2)继承的体系结构
A:多个具体的对象,不断的向上抽取共享的内容,最终形成一个体系,这个体系叫继承体系。
B:继承体系的学习和使用原则
- 学习顶层的内容,因为他是整个体系的共性内容。
- 创建子类使用,也就是使用底层的具体对象。
(3)继承的特点
- A:java中只能单继承,不能多继承。
- java可以有多重(层)继承。
(4)继承的好处:
1、提高代码的复用性
2、继承的出现让类与类之间产生的关系,提高了多态的前提。
(5)子父类中的成员关系
A、成员变量
在子类方法中使用一个变量时:
首先,在方法的局部变量中找这个变量,有则使用。
否则,在本类中找成员变量,有则使用。
否则,在父类中找成员变量,有则使用。
否则,报错。
B、成员变量
用子类对象使用一个方法时:
首先,在子类中找这个方法,有则使用。
否则,在父类中找这个方法,有则使用。
否则,报错。
重写和重载的区别?
重载:在同一个类中,方法名相同,参数列表不同。重载可以改变返回值类型。
重写:在不同类中(要有继承关系)
方法声明相同(返回类型、方法名、参数列表相同)。
重写需要注意:
- 子类方法的访问权限要大于等于父类的访问权限。
- 静态只能重写静态,但是这种情况不会出现。
构造方法
子类的实例化过程:
- 子类创建对象时,会先去创建父类的对象。
- 默认是去调用父类的无参构造方法。
子类的构造方法,第一行默认是super();
原因:子类继承父类的成员使用,使用这些成员变量前必须初始化,而他们是父类的成员,所以必须通过父类进行初始化,所以会先创建一个父类对象。
当父类没有无参构造时,必须使用this或者super调用其他的构造方法。
(6)this和super的区别
this:代表本类对象的引用。
super:代表父类的存储空间。
18、final关键字(重点)
(1)最终的意思,可以用来修饰类,方法,变量。
(2)
- final修饰的类不能被继承。
- final修饰的方法不能被重写。
- final修饰的变量是一个常量。只能被赋值一次。
- 内部类只能访问final修饰的局部变量。
19、抽象类(重点)
(1)对个类有相同的方法声明,但是方法体不一样。这个时候,我们考虑把方法声明进行抽取。
让子类继承后:自己去实现方法体。没有方法体的方法,我们需要用抽象标志下。
抽象类的关键字是:abstract
(2)抽象类:
该方法称为抽象方法,包含抽象方法的类就是抽象类。
(3)抽象类的特点:
A:抽象类和抽象方法都要用abstract进行修饰。
B:抽象类不能被实例化。
C:抽象类中不能有抽象方法,但是有抽象方法的类一定是抽象类。
(4)抽象类中数据的特点
成员变量
抽象类中可以有变量,也可以有常量。成员方法
抽象类中可以有抽象方法,也可以有非抽象方法。-
构造方法
- 抽象类是一个类,所以有构造方法。
- 虽然本身不能实例化,但可以给子类实例化使用。
(5)抽象类中的问题
- A:抽象类中是否有构造方法?能不能被实例化?如果不能,为什么有构造方法?
抽象类有构造方法,抽象类中的构造方法供子类实例化调用。 - B:抽象关键字abstract不可以和哪些关键字共存?
1、private:
私有内容子类继承不到,所以不能重写。但是abstract修饰的方法,要求被重写,两者冲突。
2、final
final修饰的方法不能被重写。
而abstract修饰的方法,要求被重写,两者冲突。
3、static
假如一个抽象方法能通过static修饰,那么这个方法,就可以直接通过类名调用。而抽象方法是没有方法体的,这样的调用无意义,所以不能加static。
- C:抽象类中可以不可以没有抽象方法?如果可以,这样的类有什么用吗?
答:抽象类可以没有抽象方法,抽象类中没有抽象方法的作用,只是味蕾不让别的类建立该抽象类的对象。
20、接口Interface
(1)定义
当一个类中的方法都是抽象的时候,java提供了另一种表示方法,叫接口。
(2)接口的成员特点
- 成员变量
是常量,默认修饰 public static final - 成员方法
都是抽象的,默认修饰 public abstract
(3)关系
- 类与类的关系
是继承关系,类与类只能单继承,可以多级继承。 - 类与接口的关系
是实现关系,一个类可以实现多个接口。类在继承一个类的同时可以实现多个接口。 - 接口与接口的关系
是继承关系,接口可以多继承接口。
(4)接口的特点
- 是对外保留的规则
- 是功能的扩展
- 接口的出现降低耦合性
- 耦合:类与类之间的关系
- 内聚:类完成功能的能力
- 编程规范:低耦合,搞内聚
- 接口可以多实现。
如:CPU和主板、笔记本的USB插口、插座。
(5)接口和抽象类的区别
抽象类只能被单继承
接口可以多实现,接口的出现避免了多继承的局限性。-
抽象类中的数据特点
- 成员变量:可以是变量,也可以是常量。
- 成员方法:可以是抽象方法,也可以是非抽象方法。
- 构造方法:有构造方法。
-
接口中的数据特点
- 成员变量:是常量。默认修饰 public static final
- 成员方法:都是抽象方法。都要默认修饰 public abstract
- 构造方法:没有构造方法。
抽象类中定义的是继承体系中的共性功能
接口中定义的是继承体系中的扩展功能。抽象类被继承是“ is a” 关系 :xx 是yy 的一种
接口被实现是“ like a” 关系:xx像yy的一种
21、多态
(1)同一个对象,在程序不同时刻的多种运行状态。
例如:动物、狗是狗,狗是动物。水(气态、固态、液态);
(2)多态的前提
- 存在继承关系或者实现关系
- 有方法重写
- 父类(接口)引用指向子类(实现)对象
(3)多态的好处和弊端:
好处:多态的存在提高了程序的扩展性和后期维护性。
弊端:虽然可以预先使用,但是只能访问父类中已有的功能,运行的是后期子类的功能内容。不能预先使用子类中定义的特有功能。
(4)多态中对象调用成员的特点。
Fu f = new Zi();
- 成员变量
- 编译看左边,运行看右边。
- 成员方法
- 编译看左边,运行看右边。
- 静态方法
- 编译看左边,运行看左边。
(5)多态的思想
只会同一批对象做事情,举例:带兵打仗,下课等等。
22、instance关键字
- 用于判断某个对象是否是某种类型
- 格式
- 对象名 instance 子类(实现)名
23、Object类
(1)概述
Object类是所有类的根类(超类,所有类都继承或间接继承Object类),java中提供的类以及我们自定义的类都直接或者间接的继承自Object类。
(2)Object类中的方法
void finalize();
当垃圾回收器确定不存在该对象的更多引用时,由于对象的垃圾回收器调用此方法。Class getClass();
获取对象的子界面文件的描述类。
String name = s.getClass().getName();int hashCode();
获取对象的哈希值。其实就是对象的内存地址值十进制表示。String toString();
返回对象的字符串表示
getClass().getName()+"@"+Integer.toHexString(hashCode());
一般我们输出对象名的时候,其实底层调用的就是toString()方法。这种返回没有意义,所以我们会重写这个方法,显示类的成员变量信息。boolean equals(Object obj);
用于比较两个对象的地址值是否相同。
我们获取对象后,比较它的地址值意义不大。所以也会用这个方法进行重写。
(4) == 和 equals的用法:
- ==怎么用?
- 可以用于比较基本数据类型,比较的就是基本数据类型的值是否相等。
- 可以用于比较引用数据类型,比较的是对象的地址值是否相等。
- equals怎么用?
- equals只能用于比较引用数据类型。
- Object提供的equals是用于比较对象地址值是否相同。
- 自定义类中,如果重写equals方法,那么就是按照你自己的需求来比较。
24、package关键字
(1)概念
包:就是文件夹,用于区分不能包下的类名。
(2)好处
对类进行分类管理
-
给类提供多层命名空间
- aaa.Demo
- bbb.Demo
写在程序文件的第一行
包也是封装的一种形式
25、import 关键字
(1)导入包的关键字
(2)格式
import 包名;
(3)注意
- 一个程序文件夹中只有一个package,可以有多个import。
- 用来导报中的类,不能导包中的包。
- 通常写import mypacg.Demo
(4)关键字顺序
类,包,导报这些关键字的顺序
包 → 导包 → 类
26、不同的修饰符可以修饰哪些内容
27、内部类(次重点)
(1)定义
把一个类定义在某个类中,这个类就被成为内部类,内置类,嵌套类。
(2)访问特点
- 内部类可以直接访问外部类中的成员,因为内部类持有外部类的引用。
格式: 外部类名.this - 外部类要想访问内部类的成员,不想创建对象访问。
(3)内部类的访问格式:
- 当内部类定义在外部类的成员位置,而且非私有,则可以在其他外部类中直接建立内部类对象。
格式:外部类名.内部类名 变量名 = new 外部类对象.内部类对象
如: Outer.Inner in = new Outer().new Inner(); - 当内部类在外部类成员位置,且被static修饰时
- 外部类其他类可以直接访问静态内部类的非静态成员。
- 格式: new 外部类名.内部类名().内部类成员。
- 如:new Outer.Inner().function();
- 外部其他类可以直接访问静态内部类的静态成员。
- 格式:new 外部类.内部类名.内部类成员
- 如:new Outer.Inner.function();
- 外部类其他类可以直接访问静态内部类的非静态成员。
(4)什么时候使用内部类
假如A类和B类,A类想直接访问B类的成员,B类访问A类的成员的时候,需要创建A类对象进行访问,这个时候,就可以把A类定义为B类的内部类。
(5)内部类的位置
- 成员位置
- 可以被private修饰(Body , Heart)
- 可以被static修饰(它访问外部类的成员必须是静态的。);
- 局部变量
- 可以直接访问外部类中的成员,因为还持有外部类的引用。
- 可以可以直接访问局部成员,但是局部成员要用final修饰。
- 如:new Outer.Inner.function();
(6)通过class文件我们就可以区分是否带有内部类,以及类的位置。
- Outer$Inner:成员内部类
- Outer$1Inner:局部内部类
28、匿名内部类(局部内部类的简写)(重点)
(1)前提
继承一个类或者实现一个接口。
(注意:不要弄混内部类的前提和多态的前提)
(2)格式
new 父类名或接口名(){
重写父类方法或者实现接口中的方法。
也可以自定义其他方法。
};
(3)什么时候定义匿名内部类?
匿名内部类只是为了简化书写,匿名内部类有局限,通常定义匿名内部类时,该类不会超过三个方法。
(4)匿名内部类的好处和弊端:
- 好处
- 简化代码书写
- 弊端
- 不能直接调用自己特有的方法
- 不能执行强转动作
- 如果该类里面方法较多,不允许使用匿名内部类。
29、模板设计模式:
在定义功能时,功能的一部分是确定的,有一部分是不确定的,而且确定的部分在使用不确定的部分,可将不确定的部分暴露出去,由该类的子类去完成。
如:求一段程序的运行时间。
30、异常
(1)定义
程序运行过程中的不正常现象叫异常。
(2)特点
导致程序运行部正常的现象很多,所以就有很多的异常对象。而这些异常对象存在着共性的内容,所以可以不断进行抽取。最终形成了异常的体系结构。
异常体系的根类是:Throwable
Throwable:
|--Error:重大的问题,我们处理不了。也不需要编写代码处理,比如内存溢出。
|--Exception:一般的错误,是我们编写代码进行处理的。
|--RunntimeException:运行时异常,这个我们也不需要处理。其实就是为了让他在运行时出问题,然后我们再回来修改代码。
(3)异常分类
异常分类有两种:
- 编译时被检测异常:
- 该异常在编译时,如果没有处理(没有抛出也没有try),编译失败。
- 该异常被标识,代表这个可以被处理。
- 运行时异常(编译时不检测)
- 在编译时,不需要处理,编译器不检查。
- 该异常的发生,建议不处理。让程序停止。需要对代码进行更改。
(4)异常体系的特点:
异常体系中的所有类及其子类对象都具备可抛性,也就是说可以被throw和throws关键字操作。
(5)main方法是如何处理异常的。
- 在main里面编写的代码进行处理。
- 交给jvm自己进行处理。采用的是jvm的默认处理方式(相当于调用了异常对象的printStackTrace()方法)。
(6)Throwable类的学习。
- getMessage():获取异常信息,返回字符串。
- toString():获取异常类名和异常信息,返回字符串。
- printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
(7)异常处理。
1)try...catch...finally
基本格式
try
{
可能出现异常的代码
}
catch(异常对象)
{
异常处理代码
}
finally
{
释放资源
}
变形格式:
try...catch
try...catch...catch...
try...catch...catch...finally
多个异常被捕获的时候,记住一个原则:
先捕获小的,再捕获大的。
finally:永远被执行,除非退出jvm,Ststem.exit(0);
面试题:
1.final、finally、finalize的区别。
final是最终的意思,它可以用于修饰类,成员变量,成员方法。
它修饰的类不能被继承,它修饰的变量是常量,它修饰的方法不能被重写。
finally:是异常处理里面的关键字。
它其中的代码永远被执行,特殊情况:在执行它之前jvm退出。System.exit(0);
finalize:是Object类中的一个方法。
它是垃圾回收器调用的方法。
2.假如chtch中有return语句,finally里中的代码会执行吗?
在return前执行finally里的代码。
(8)Exception和RunntimeExpection的区别
Exception:一般性错误,是需要我们编写代码进行处理的。
-
RuntimeException:运行时异常,这个我们需要处理。其实就是为了让他在运行时出现问题,然后我们回来修改代码。
- 在用throws抛出异常的时候,如果这个异常属于RuntimeException的体系的时候,我们在调用的方法不可以处理(RuntimeException和RuntimeException的子类)。
- 在用throws抛出异常的时候,如果这个异常属于Exception的体系时,我们调用的地方必须进行处理或者抛出。
(9)自定义异常
定义一个类继承Exception或者RuntimeException。
为了让该类自定义类具备可抛性。
让该类具备操作异常的共性方法。
class MyExcepiton extends Exception
{
MyExcepiton(){}
MyExcepiton(String message)
{
super(message);
}
}
class MyException extends RuntimeException
{
MyExcepiton(){}
MyExcepiton(String message)
{
super(message);
}
}
(10)throws和throw的区别
- 有throws的时候可以没有throw。
- 有throw的时候,如果throw抛的异常是Exception体系,那么必须有throws在方法上声明。
- throws用于方法的声明上,气候跟的是异常类名,后面可以跟多个异常类,之间用逗号隔开。
- throw用于方法体中,其后跟的是一个异常对象名。