面试冲刺
花倩
#JAVA基础,OOP,API知识点复习
##语言基础:
###变量,8种基本数据类型
变量的声明以及初始化(定义)
数据类型 变量名 = value;
注意点:变量名的命名规则
java中的数据类型:2类:基本数据类型 引用类型
基本数据类型:8种
byte short int long float double boolean char
1字节 2 4 8 4 8 1 2
char:字符型
char在内存中是如何保存的?
是以unicode编码保存在内存中的
\u4e00-\u9fa5 所有的中文
向文件中写入数据时:字符数据–>字节数据 写入文件 编码
从文件中读取数据时:字节数据–>字符数据 读取数据 解码
字符的编码解码问题:
UTF-8:一个英文占1个字节 一个中文占3个字节
GBK:一个英文占1个字节,一个中文占2个字节
###分支
if…else…
switch…case…
break关键字:作用在分支中,跳出当前分支
switch…case中注意点:
1.每条分支后都要有break,若没有,执行完当前分支,继续执行下面的分支,直到遇到break为止。
2.swith(value)value的数据类型只能是int String 枚举类型
###循环
1.while:
2.do…while:适用于先执行后判断的循环
3.for:适用于次数固定的循环
for(int i = 0;i
4.foreach循环/增强for循环
for(数据类型 引用:集合/数组){
引用指向的就是遍历到的具体的元素
}
意义:用于对集合/数组中元素的遍历
###数组:线性表结构
1.数组的声明以及初始化:
数据类型[] array = new 数据类型[length]
数据类型[] array = {val1,val2,val3…};
数据类型[] array = new 数据类型[]{val1,val2,val3…};
2.数组的访问:
对数组元素的访问:通过下标访问
数组长度的访问:array.length;
数组的遍历:for循环, foreach
3.数组的复制:
T[] - Arrays.copyOf(src,newLenth):数组的扩容
int[] ary = {1,2,3};
要求:对ary扩容,扩容后的长度为5
int[] newAry = Arrays.copyOf(ary,5);
newAry:1,2,3,0,0
要求:对ary缩容,缩容后的长度为2;
newAry = Arrays.copyOf(ary,2);
newAry:1,2
System.arrayCopy(src,int offset,dest,int start,int len)
4.引用数组:数组中的元素类型是引用类型,就叫做引用数组,数组本身就是引用类型
String[] strs = new String[3];
int[][] ary = new int[2][3]; 引用数组
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xbUzHnis-1570152301196)(1.png)]
###方法
方法的定义:
访问控制修饰符 返回值类型 方法名(参数列表){方法体}
访问控制修饰符:public protected 默认 private
变量分类:成员变量 局部变量
成员变量保存在内存中的堆中,局部变量保存于栈中
参数列表:中的参数属于局部变量,保存于栈中
可变参数:数据类型…变量名
可变:参数个数可变
可变参数注意点:
1.如果参数列表出现可变参数,那么可变参数一定是位于参数列表最后的
2.参数列表位置最多只能有一个可变参数
3.可变参数的底层是数组,可变参数的访问方式和数组是一样的
4.如果方法的参数列表有可变参数,那么可以传递一个数组过去
eg:
public void test(){
//demo(1,3,23,4);
//可以传递一个数组给可变参数
int[] ary = new int[3];
demo(1,ary);
}
//正确写法
public void demo(int a,int...b){
a:1
//遍历输出b中的所有值
对b进行for循环遍历
}
//错误写法1:
public void demo(int...a,int b){}
//错误写法2:、
public void demo(int...a,int...b){}
注意点:面试题:Java中的参数传递是引用传递还是值传递?
Java中参数的传递只有值传递
重载:overload
在同一个类中,存在多个方法名相同,参数列表不同的方法,就构成了方法的重载。和方法的返回值,修饰符没有关系
eg:
class Super{
public void test(){...}
}
class Sub extends Super{
public void test(int a){...}
}
以上两个方法是否构成重载? 构成
##OOP
###类和对象
类和对象的关系:
类是模板,对象是经由模板创建出来的一个具体的实例个体。
对象的创建:new
构造方法:作用:初始化
分类:无参构造方法 有参构造方法
一个类中最多只有一个无参构造方法,可以有多个有参构造方法
###问题:面向对象的三大特征?
###内存管理:
JVM中内存分成3块区域:方法区 堆(heap) 栈(stack)
方法区:属于类的
堆:对象,成员变量
对象/成员变量的生命周期
对象创建后,通过引用指向对象来使用对象中的内容,当没有任何引用指向这个对象时,表示此对象成为了垃圾,等待被GC销毁
GC:垃圾回收机制,GC的回收是不确定的,但是有一个时刻GC一定会工作:当内存不足时。
如果程序员想立即调用GC,可以通过Sysytem.gc()来建议GC回收
内存泄露:分配出去的内存回收不回来
内存溢出:剩余的内存不足以分配给请求的资源
java.lang.OutOfMemoryError
内存泄漏累计到一定程度会造成内存溢出
内存溢出一定是由内存泄漏造成的吗?
不一定,也可能是由于请求的资源大小大于JVM的内存大小造成的。
int[] ary = new int[800000000]
栈:局部变量(参数列表) 栈帧
案例:
public class Demo01 {
public static void main(String[] args) {
int i = 3;
String str = “gbk”;
char[] chs = {‘a’,‘b’,‘c’};
Demo01 demo01 = new Demo01();
demo01.change(str, chs);
System.out.println(str); //gbk
System.out.println(chs); //kbc
}
public void change(String str1,char[] chs){
str1 = "abk";
chs[0] = 'k';
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xSpQo5RQ-1570152301199)(2.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uIf8UqcK-1570152301200)(3.png)]
###继承:
extends 子类 extends 父类
继承的特点:
Java中类的继承是单继承的
具有传递性
继承中不继承的成员:
构造方法
私有成员
static成员:static成员是属于类的,而继承是面向对象的,在类中没有继承这一概念
问:面向对象的三大特征: 封装 继承 多态
继承中构造方法的调用问题:
创建子类对象,会先调用父类的构造方法,之后继续执行子类的构造方法
构造方法作用:初始化
继承中构造方法的调用问题:
class Super{
int a = 6;
public Super{
test();
}
public void test(){
System.out.println(a);
}
}
class Sub extends Super{
int a = 8;
public Sub(){
test();
}
public void test(){
System.out.println(a);
}
}
main: new Sub(); 0 8
考点:
1.创建对象时会对成员变量先进行默认初始化
2.构造方法中先执行super(),之后对成员变量进行人为初始化
3.调用一个方法,此方法重写了,调用的方法到底是父类的还是子类是通过看运行期创建的对象来决定的
重写:重写规则:
在具有继承关系的两个类中,存在
方法签名相同
方法的访问控制修饰符:子类>=父类
方法的返回值:
如果是基本数据类型,必须相同
如果是引用类型,子类<=父类
子类的返回值类型可以和父类一致,也可以子类的返回值类型是父类返回值类型的子类
如果方法声明有异常抛出:
子类抛出和父类一致的异常
子类抛出父类异常的一部分,子类可以抛出父类异常的子类异常
子类不可以抛出父类中没有的异常,也不可以抛出父类异常的父类异常
不论是通过父类的引用还是子类的引用指向子类对象,调用的方法一定是子类重写后的方法。
前提:子类重写父类中的test方法
Super sup = new Sub();
Sub sub = new Sub();
sup.test() //调用到的是子类中重写后的方法
sub.test() //调用到的是子类中的方法
多态:
对象的造型:
对象的向上造型:
Super super = new Sub();
缺点:通过此引用访问不到子类中特有的成员,若想访问到子类中的特有成员,可以通过向下造型实现。
对象的向下造型:
Super super = new Sub();
Sub sub = (Sub)super; //正确的
问:以下的向下造型是否正确?
前提:父类 Person 子类:Student Teacher
情景一:正确的
Person per = new Student();
Student stu = (Student)per;
情景二:错误的
Person per = new Student();
Teacher tea = (Teacher)per;
情景三:错误的
Person per = new Person();
Student stu = (Student)per;
强调点:
1.向上造型,向下造型都是针对具有继承关系的父子类的
2.向下造型是否成功,看引用指向的运行时对象的类型是否和造型成的类型一致。
对象的强制造型
interface: Enemy:getScore()
class SuperCls
class SubCls ,SubCls2 extends SuperCls implements Enmey
若现存在SuperCls cls = 子类对象(不确定),若想调用子类对象中的getScore方法,此时就需要进行强制造型
Enemey en = (Enemy)cls;
en.getScore();
判断:instanceof
if(obj instanceof Enemy){}
###static和final关键字
staitc关键字:
可以用来修饰:不论修饰的是什么,作用都是属于类的
方法:调用:通过类名.方法
成员变量:
调用:通过类名.成员变量
static int a = 5;
此成员变量在类加载时期进行初始化且只初始化一次。和对象创建多少次无关。
eg:
class T{
static int a = 10;
int b = 3;
main:
T t1 = new T();
t1.b++;
T.a++; 11
T t2 = new T();
T.a++; 12
System.out.println(T.a); //12
System.out.println(t2.b); //3
}
代码块:此代码块在类加载时期执行完成,且只执行一次
final关键字:
可以用来修饰三类内容:
类:类不能被继承
方法:方法不能被重写
变量:变量一旦初始化之后,值不能再改变
static final可以配合使用来修饰常量
public static final int STUDENT_AGE = 23;
###抽象和接口
抽象:abstract
抽象方法和抽象类:
二者关系:如果一个类中有抽象方法,那么这个类一定是抽象类,反之,如果一个类是抽象类,类中不一定有抽象方法。
接口:interface
成员只有2种:常量 抽象方法、
在接口中定义常量可以直接写成 数据类型 常量名 = val;因为接口中默认提供了public static final类修饰定义的常量
同理,在接口中定义抽象方法,可以只写返回值类型和方法签名,因为接口中默认提供了 public abstract
接口的实现:implements
注意点:
1.是可以多实现的
2.接口之间是可以继承,且是可以多继承的、
3.继承和实现是可以混合使用的,但是一定是继承在前实现在后
接口的出现是对Java中类的单继承不足做出的弥补。
抽象类和接口之间的联系:
如果一个类实现了该接口,但是没有完全重写该接口中的所有抽象方法,此时这个类就成为了抽象类。
此种用法在JavaAPI中很常见,意义:
interface A,抽象方法有:t1() t2() t3()
已知此接口将来会有n个实现类,但是这些实现类中对于t1方法的方法体实现都是一致的,而对t2和t3方法的实现是各自不同的。此时就可以在接口和n个实现类中间加入抽象类,在此抽象类中实现公共的内容。
interface A{
void t1();
void t2();
void t3();
}
abstract class MiddleCls implements A{
@override
t1(){System.out.println("hello")}
}
class B extends MiddleCls{
@override
t2(){B类中自己独特的做法}
@override
t3(){B类中有自己的做法}
}
class C extends MiddleCls{
@override
t2(){C类中自己独特的做法}
@override
t3(){C类中有自己的做法}
}
class D extends MiddleCls{
@override
t2(){D类中自己独特的做法}
@override
t3(){D类中有自己的做法}
}
###内部类,lambda表达式
1.class Outter{
int a = 3;
public void test(){}
class InnerCls{
int b = 4;
public void demo(){}
}
}
此时内部类通常是供外部类使用的,用法:在外部类的构造方法或方法中直接创建内部类对象,并调用内部类对象中的成员。
//用法1
public class OutterCls {
int a = 4;
public static void main(String[] args) {
OutterCls cls = new OutterCls();
cls.test();
}
public void test(){
//创建内部类对象并调用其中的成员
Inner inner = new Inner();
System.out.println(inner.b);
inner.demo();
}
public class Inner{
int b = 3;
public void demo(){
System.out.println(“内部类中的成员方法”);
}
}
}
//用法2
public class Test {
public static void main(String[] args) {
//访问OutterCls中的内部类中的成员
//先创建外部类对象,通过外部类对象再创建内部类对象
OutterCls cls = new OutterCls();
Inner in = cls.new Inner();
System.out.println(in.b);
in.demo();
}
}
局部内部类:
写法:
class OutterCls{
int a = 4;
public void test(){
String s = “hello”;
class InnerCls{
int b = 3;
public void demo(){
System.out.println(s);
}
}
//创建并使用
InnerCls cls = new InnerCls();
cls.b;
cls.demo();
}
}
注意点:
JDK1.8中在局部内部类中访问其所属方法的局部变量是没问题的,
但是在1.8之前,在局部内部类中要想访问其所属方法的局部变量,这个局部变量必须是final修饰的。
匿名内部类:
使用场景:如果实现了接口或要继承抽象类/类,此时就可以用匿名内部类是实现。
要求:使用匿名内部类创建一个线程对象(Runnable)
Runnable r = new Runnable(){
public void run(){
....
}
}
new Thread(r).start();
lambda表达式:JDK1.8的新特性、
如果匿名内部类实现的接口是功能性接口(只有一个抽象方法的接口),此时可以使用lambda表达式
写法:()->{}
参数列表中参数的数据类型都可以省略
如果重写的接口中的方法的参数列表只有一个参数,此时()可以省略的
如果重写的方法体只有一句语句,那么{}可以省略,如果有return,return可以省略
#JAVA基础,OOP-选择题
A.10
B.7
C.13
D.14
for (int n = 2; n <= 1000; n++) {
空白处
if (s == n) {
System.out.println(n);
}
}
下列选项中,空白处可以填入的代码是:( AC)。
A.int s = 0, n1 = n; while (n1 > 0) { int t = n1 % 10; s += t * t * t; n1 /= 10; }
B.int s = 0, n1 = n; while (n1 > 0) { int t = n1 / 10; s+= t * t * t; n1 %= 10; }
C.int s = 0; for(int n1 = n; n1>0; n1 /= 10) { int t = n1%10; s += t * t * t; }
D.int s = 0; for(int n1 = n; n1>0; n1 %= 10) { int t = n1 / 10; s += t * t * t; }
int x=6, y=10, k=5;
switch( x % y )
{
case 0: k=x*y;
case 6: k=x/y;
case 12: k=x-y;
default: k=x*y-x;
}
A.60
B.5
C.0
D.54
class Test{
public static void main(String[] args){
doSomething(1);
doSomething(1,2);
}
//insert code here
}
在程序中插入下列哪一行代码可以编译通过:
A static void doSomething(int[] args){}
B static void doSomething(int… args){}
C static coid doSomething(int…args,int x){}
D static void doSomething(int x,int…args){}
####5.(单选)关于下列代码说法正确的是:
public class A {
private int counter = 0;
public static int getInstanceCount() {
return counter;
}
public A() {
counter++;
}
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
A a3 = new A();
System.out.println(A.getInstanceCount());
}
}
A.该类编译失败
B.输出:1
C.输出:3
D.输出:0
class Base {
int i = 99;
public void amethod() {
System.out.println("Base.amethod()");
}
Base() {
amethod();
}
}
public class RType extends Base {
int i = -1;
public static void main(String argv[]){
Base b = new RType();
System.out.print(b.i+"\t");
b.amethod();
RType r = (RType)b;
System.out.print(r.i+"\t");
}
public void amethod(){
System.out.print("RType.amethod()"+"\t");
}
}
A RType.amethod -1 RType.amethod -1
B RType.amethod 99 RType.amethod -1
C 99 RType.amethod 99
D 编译时错误(Compile time error)
class Base {
Base() { System.out.print("Base"); }
}
public class Alpha extends Base {
public static void main( String[] args ) {
new Alpha();
new Base();
}
}
A.Base
B.BaseBase
C.程序编译失败.
D.程序运行但没有任何输出
#程序题
####2.一个数组中只有0,1两种数字,进行排序,0全部在前,1全部在后
(RType)b;
System.out.print(r.i+"\t");
}
public void amethod(){
System.out.print(“RType.amethod()”+"\t");
}
}
A RType.amethod -1 RType.amethod -1
B RType.amethod 99 RType.amethod -1
C 99 RType.amethod 99
D 编译时错误(Compile time error)
class Base {
Base() { System.out.print("Base"); }
}
public class Alpha extends Base {
public static void main( String[] args ) {
new Alpha();
new Base();
}
}
A.Base
B.BaseBase
C.程序编译失败.
D.程序运行但没有任何输出
#程序题
####2.一个数组中只有0,1两种数字,进行排序,0全部在前,1全部在后