【面试八股】Java回顾:基础编程(基本语法、面向对象、异常处理)

前言

摩尔定律:当价格不变时,集成电路上可容纳得元器件的数目,约每隔18-24个月就会增加一倍,性能也会提升一倍;

计算机的基本概念属于图灵,而冯诺依曼让世界认识了由图灵引入的计算机基本概念;

B/S架构:Browser Server 浏览器-服务端
C/S架构:Client Server 客户端-服务端

前景:
35岁的问题其实看自己,后期可以管理岗、可以创业等等;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一定要以技术为基础,后面有了几年工作经验后到了分岔口,再选择资深技术还是管理路线;
否则,一开始就像干别的,等回过头技术都忘得差不多了;

学编程:三分看,七分练;

Java语言概述

发展和核心

因为本身有些基础,所以就写一些重点以及容易忽视的注意点吧,快速过完一遍即可;

学习路线:
JavaSE -> JavaWeb -> JavaEE框架(SSM) -> JavaEE高级 -> Java就业面试指导;

Java是学习JavaEE、大数据、Android开发的基石;
在这里插入图片描述
在这里插入图片描述
C开发效率低,运行效率高,而Java开发效率高,运行是对C的封装,效率稍低;
Object-C主要用于开发苹果系统;

Java由SUN(Stanford University Network 斯坦福大学网络公司)推出; Java是一个岛名,岛上生产咖啡,得来Java的名字和图标;
在这里插入图片描述
Java SE (Java Standard Edition)标准版,支持桌面级应用;
Java EE 企业版,开发企业环境;
Java ME 小型版,支持java程序运行在移动端;

Java的诞生正是因为James Gosling团队在开发项目时,发现C缺少垃圾回收系统,还有可移植的安全性、分布程序设计和多线程功能,需要一种跨系统、跨设备的平台;Java舍弃C中容易引起错误的指针,增加了垃圾回收器功能;

Java语言特点:

  • 面向对象;
    • 两个基本概念:类、对象;
    • 三大特性:封装、继承、多态
  • 健壮性;
    • 吸收C/C++优点,除去其影响健壮性的部分,提供相对安全的内存管理和访问机制;
  • 跨平台性;
    • Write once,Run anywhere,基于Java虚拟机JVM,程序在对应操作系统版本的JVM上跑;

Java核心:JVM垃圾回收机制

JDK(java开发工具包)包括JRE(java运行环境);
在这里插入图片描述
在这里插入图片描述
Windows命令行不区分大小写!

在这里插入图片描述

注释

文档注释:对缩写程序进行解释说明,增强可读性,方便自己和他人;
单行、多行注释不参与编译,且多行注释不可以嵌套使用;
文档注释内容可以被JDK提供的工具 javadoc所解析,生成一套网页形式的说明文档;
格式:

/**
	@author 指定java程序的作者
	@version 指定源文件的版本
	内容
*/

  • 在一个Java源文件中,可以声明多个class,但是只能最多有一个类声明为public,这个类还要跟 java 的文件名一致,保证public类名和文件名一样!
  • 程序的入口是 main() 方法,格式固定;
  • 编译以后,会生成一个or多个字节码文件;字节码文件的文件名与java源文件的类名一致;
  • 一句话说明IDEA的优点:他懂你!

基本语法

java名称命名规范:

  • 包名:多单词组成时所有字母都小写;
  • 类目、接口名:多单词组成时,所有单词的首字母大写,大驼峰;
  • 变量名、方法名:小驼峰;
  • 常量名:所有字母都大写,单词间用下划线分割;

java定义变量的格式:数据类型 变量名 = 变量值;

主函数变量不会默认初始化;

在这里插入图片描述

进制转换:
0b开头 二进制
0开头 八进制
0x开头 十六进制

-128的补码 1000 0000


Scanner
在这里插入图片描述


数组
在这里插入图片描述
在这里插入图片描述
数组初始化为0 or false or null;

只要是 new 的,就是个新的,如果不 new ,那就是指针指向了那里,弱copy;


面向对象

OOP: Object-oriented programming,面向对象编程

面向过程中,主体是执行者,面向对象中,主体是指挥者;
内存解析:
在这里插入图片描述

属性默认初始化 VS 局部变量默认初始化:
属性:类的属性,根据其类型,都有默认初始化值,0、null、false等等;
局部变量:没有默认初始化值,即在使用之前,都要进行显示初始化;

而且,属性(非static)加载到 heap 中,而局部变量加载到 stack 中;


可变个数形参
类型 ... 形参名

  • 当调用可变形参方法时,传入参数可以是0个、1个,多个;
  • 可与同类的同名方法构成重载(若参数为同类型数组,则报错重复定义),不冲突;
    在这里插入图片描述
  • 可变个数形参在方法的形参中,必须声明在末尾;

关于变量的赋值需要注意的地方:

  • 对于基本数据类型,变量之间的赋值,就是把一个变量的值给另一个变量,二者互不影响;
    在这里插入图片描述
  • 对于引用数据类型,变量赋值是赋的地址,即二者指向堆中的同一对象实体,相互影响;
    在这里插入图片描述

方法的形参传递机制:值传递
基本数据类型,传递的是实参的值;
引用数据类型,传递的是引用的地址;

如果要把对形参的修改同步到实参,非得专门封装成类吗?
那 Interger 是干啥用的?

放一个视频中的笔试题:
在这里插入图片描述
法一:函数内输出并退出程序
在这里插入图片描述
法二:重置打印流
在这里插入图片描述


程序设计追求:高内聚、低耦合

  • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
  • 低耦合:仅对外暴露少量的方法用于使用;

封装提高可维护性、可扩展性;
比如变量私有化,通过setxxx() getxxx()获得设置值;不对外暴露的私有方法;

为什么需要封装性:额外的限制条件!
在这里插入图片描述

四种访问权限
在这里插入图片描述
在这里插入图片描述

修饰类的话,只能使用:缺省、public!
一般一个源文件就写一个类;


JavaBean
在这里插入图片描述
在这里插入图片描述


this
why?
形参取名要有意义,把形参赋给属性容易重名,所以使用this用以区分,this表示当前对象;
在这里插入图片描述
导致冗余,所以使用this调用构造器减少代码量;在一个方法中调用构造器,this()调用空参构造器;
注意:
在这里插入图片描述


package 、 import
why?
为了更好实现项目中类的管理,提出package;
使用package声明类or接口所属的包,放在首行,包名都小写;

同一个包下不能命名同名的类、接口;

java主要包
在这里插入图片描述

MVC设计模式
在这里插入图片描述
在这里插入图片描述

import
why
配合package使用,在文件中import指定包下的类or接口;
导入所有类:import xxx.xxx.*

如果不同包下的两个类名相同,就不能用import了,至少有一个类要用全类名的方式显示:
在这里插入图片描述


继承
why?
减少代码冗余,提高代码复用性;
便于扩展;
为多态提供基础;

父类私有属性也会被继承,只是因为封装性,私有属性不可见而已;
一旦子类继承父类后,子类就获得了父类所有的属性和方法;

C++允许多继承,而Java只允许单继承,一个人只能有一个父亲;
在这里插入图片描述
不同包的子类中,不能调用private 和 default 的属性和方法;

子类对象实例化过程:
在这里插入图片描述
虽然调用了父类的构造器,但自始至终都只创建了一个对象;

Object类

在这里插入图片描述
在这里插入图片描述
==equal的区别:
==
基本数据类型,只要值相等就行,不一定类型要相同;
引用数据类型,比较两个对象地址值是否相同;
equals
因为它是方法,所以基本数据类型玩不了,后面会将基本数据类型对于的包装类;
equal在object类中的实现和==是一样的;而Stirng、Data、File、包装类等对equal方法进行了重写,是比较内容;
在这里插入图片描述
实现就是:先比较两个引用地址是否相同,如果相同直接return true,否则,对内容逐个比较;

toStirng
在这里插入图片描述
发我们输出一个对象的引用时,实际上就是调用当前对象的toString方法;


重写override
在这里插入图片描述
说实话,在java中,我认为override就是 overwrite,二者没有必要的区分,都是子类重写了父类的方法,或者子类实现了抽象类的方法,子类实现了接口;
或者 可以说 java没有overwrite!


super
why?
如果子类重写了父类的方法,那么在子类中调用该方法,会默认调用重写后的那个方法(属于子类);
super就是用于表示父类的结构,可以通过它调用父类的方法,即调用被重写的方法;

对于子类的属性和方法this.xxx,现在子类里面找属性or方法,子类没有再去父类找;
super.xxx则直接去父类中找;

也可以通过super调用父类的构造器,形式跟this差不多,super(形参列表),也要声明在首行;
this()super()只能二选一,不能同时出现,默认调用父类的空参的构造函数;


多态性
一个对象多种形态;
基类 对象名=new 子类()
即父类的引用指向子类的对象;
通过引用可以调用父类的方法,而调用子类重写了父类的方法时,默认调用的还是子类重写父类的方法;
编译时认为调用的父类的方法,看变量的类型,而 运行时调用的子类的方法;

总结:编译看左边,运行看右边;
多态使用前提:
① 有类的继承关系;
② 方法的重写

why有多态性?
为抽象类、接口打下基础;
子类作实参传给形参为父类的方法,就能实现子类独有的方法,即方法里面使用的时父类的对象,但具有子类的形态;
在这里插入图片描述
如果没有多态性,我就得把形参设为子类,然后一个子类对应一个方法,但方法实现的内容基本一样,很冗余、繁琐;
在这里插入图片描述
更加具体的,比如equal方法:在这里插入图片描述
obj类作为形参,任何对象作为实参,就是多态的一个体现;
在这里插入图片描述
有了对象多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法,子类特有的属性和方法不能调用;
在这里插入图片描述
那么如何才能调用子类特有的方法和属性,因为堆中new出来了,肯定有办法弄到:
man m=(man) p
强制类型转换,父转子没问题,子转父不行,不能倒着来;
在这里插入图片描述


重载和重写
在这里插入图片描述


instanceof
实例 instanceof 类型,返回Boolean值;
如果 a instanceof A为true,a instanceof B为true, 那么类B是类A的父亲;


单元测试JUnit
在这里插入图片描述
单元测试在小工程中用不用都无所谓,但在大的框架、环境下时,就显得尤为必要,因为你加一个功能不可能每次调试都跑一遍所有代码,而是需要把它单元化进行测试;

详情见:https://www.bilibili.com/video/BV1Kb411W75N?p=303

可以直接在想测试的上面 输入@Test,然后public void xxxx() {}函数进行测试,没导包会提示导包;
IDEA的单元测试还是个大学问;


包装类
有了这个类,java才算真正的面对对象
在这里插入图片描述
就是拿类把基本数据类型包了一下,还提供了很多功能;
在这里插入图片描述
默认包装类的实例为null,注意,不是对应基本数据类型的值;

包装类与基本数据类型的转换
在这里插入图片描述
自动装箱、自动拆箱
在这里插入图片描述


面试题
在这里插入图片描述
这里输出1.0,因为三元运算符会自动同一:两边的类型,即进行类型提升,所以1会变成1.0;

在这里插入图片描述
针对自动装箱方式;


static
why?
修饰所有实例共同使用的变量和方法,因为它们值都相等,避免为每个实例都开辟一块空间存放,减少空间使用;同时增加实例间的通信
通过共享变量/方法来通信;

静态变量/静态方法随着类的加载而加载,类的加载只有一次,所以静态变量的加载也只有一次,存放在方法区的静态域中,可通过类.静态变量类.静态方法调用;而对象的变量随着对象的创建而加载;
在这里插入图片描述
静态方法中不能使用 this 和 super 关键字,因为它是公共的,并不知道它指向的哪个对象或者哪个父亲;

static不能修饰构造器,构造器总是关联一个对象而被调用,所以把它声明为static是没有意义;

工具类中的方法,习惯上声明为static;


单例设计模式
设计模式与语言无关;
单例设计模式就是采用一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法;
①将类的构造器设为 private,不能在外部new了,只能在里面;
②设定静态方法供外部调用,该方法返回类内部创建的对象;
③静态方法只能访问静态变量,所以类内部产生的该类对象的变量也要是静态的;

饿汉式

public class test {
    public static void main(String[] args) {
        Bank b1 = Bank.getInstance();
        Bank b2 = Bank.getInstance();
        System.out.println(b1 == b2);// true
    }
}

class Bank {
    // 私有静态实例
    private static Bank instance = new Bank();

    // 私有构造方法
    private Bank() {

    }
    // 静态方法供外部调用返回实例
    public static Bank getInstance() {
        return instance;
    }
}

懒汉式

public class test {
    public static void main(String[] args) {
        Bank b1 = Bank.getInstance();
        Bank b2 = Bank.getInstance();
        System.out.println(b1 == b2); // true
    }
}

class Bank {
    // 私有静态实例,开始不造,用的时候再造
    private static Bank instance = null;

    // 私有构造方法
    private Bank() {

    }

    // 静态方法供外部调用返回实例
    public static Bank getInstance() {
    	// 判断是否已经造了对象
        if (instance == null)
            instance = new Bank();
        return instance;
    }
}

对比:

  • 饿汉式加载对象时间过长,但线程安全;
  • 懒汉式延迟对象创建,但目前这个写法线程不安全,可以用同步保证线程安全;

单例模式只产生一个实例,减少了系统的性能开销,当一个对象的产生需要比较多的资源时,可以用过启动时直接产生一个单例对象,然后永久驻留内存的方式解决;

单例模式应用场景
在这里插入图片描述


main方法
①作为程序入口;
②也是一个普通的静态方法,也可以调用;
③注意 main 里面不能调用非静态方法,要不把方法加static,要不通过对象调;
④作为与控制台交互的方式,通过args;


代码块
静态代码块:
①随着类的加载而加载并运行,注意静态的东西都只加载一次;像静态方法一开始加载,它在调用的时候才会运行,而代码块加载的时候就自动运行了,因为无法调用代码块;
②用于初始化类的一些信息;

非静态代码块:
①每new一个对象,非静态的东西都要重新加载一遍,所以非静态代码块也会加载并运行;
②主要用的对象创建时,属性的初始化;


属性赋值先后顺序
①默认初始化
②显示初始化 ⑤代码块赋值 (看写的顺序)
③构造器初始化
④对象.属性赋值


final
就是 const;可修饰类、变量、方法;最终的,类不可再修改的、不可再继承的,方法不可被重写的,变量不可被修改的;
final 属性在定义时可以不初始化,显式初始化、代码块初始化,构造器初始化;
方法中对final修饰的属性修改是不靠谱的;
static final 全局常量;


抽象 abstract
继承使得新子类越来越具体,而父类就需要更通用,更抽象,抽象得无法实例化,以至于能够让子类更好地去扩充他,这样的父类就是抽象类;
抽象类中一定有构造器,虽然自己不能用,但要留给子类;
抽象类的方法就没有方法体了,只有声明;
抽象 方法一定是抽象类,但抽象类可以没有抽象方法;
子类要实现(重写)抽象类的抽象方法才能实例化,否则也是个抽象类;

abstract不能修饰私有方法,因为它不可以被重写,子类不能实现它;


匿名类
匿名类的匿名对象
在这里插入图片描述
有的东西只用一次,就给他匿名;


模板方法设计模式
在这里插入图片描述


接口interface
Java的接口就是在实现多继承的效果;
接口的本质是标准、规范;
继承是是不是的关系,接口是能不能的关系,接口和类是并列的两种结构;

在这里插入图片描述
接口的属性都是全局常量,它默认就是这样,方法默认都是public abstract 的;
接口不能定义构造器,意味着不能实例化;

接口的含义:接口就是提供一种统一的’协议’,而接口中的属性也属于’协议’中的成员.它们是公共的,静态的,最终的常量.相当于全局常量。
抽象类是不’完全’的类,相当于是接口和具体类的一个中间层.即满足接口的抽象,也满足具体的实现.
如果接口可以定义变量,但是接口中的方法又都是抽象的,在接口中无法通过行为来修改属性。有的人会说了,没有关系,可以通过实现接口的对象的行为来修改接口中的属性。这当然没有问题,但是考虑这样的情况。如果接口A中有一个public访问权限的静态变量a。按照Java的语义,我们可以不通过实现接口的对象来访问变量a,通过A.a = xxx;就可以改变接口中的变量a的值了。正如抽象类中是可以这样做的,那么实现接口A的所有对象也都会自动拥有这一改变后的a的值了,也就是说一个地方改变了a,所有这些对象中a的值也都跟着变了。这和抽象类有什么区别呢,怎么体现接口更高的抽象级别呢,怎么体现接口提供的统一的协议呢,那还要接口这种抽象来做什么呢?所以接口中不能出现变量,如果有变量,就和接口提供的统一的抽象这种思想是抵触的。所以接口中的属性必然是常量,只能读不能改,这样才能为实现接口的对象提供一个统一的属性。

通俗的讲,你认为是要变化的东西,就放在你自己的实现中,不能放在接口中去,接口只是对一类事物的属性和行为更高层次的抽象。对修改关闭,对扩展(不同的实现implements)开放,接口是对开闭原则的一种体现。

https://blog.csdn.net/qq_25135655/article/details/77848166

接口通过让类去implement的方式来使用;
如果实现类实现了接口中的所有抽象方法,则此类就可以实例化;否则,还是抽象类;

Java类可以实现多个接口,弥补单继承的缺陷;
class AA extends BB implements CC,DD,EE

接口与接口间可以继承,而且可以多继承;

接口举例

public class usbTest {
    public static void main(String[] args) {
        computer c1 = new computer();
        c1.TransportData(new Printer());
        c1.TransportData(new Flash());
    }
}

class computer {
    // 电脑有一个方法,通过具有USB功能的设备进行数据传输
    void TransportData(USB usb) {
        usb.start();
        System.out.println("usb中间操作");
        usb.stop();
    }
}

// 实现USB就是实现USB的规范,比如开始工作,停止工作;
// 简单说USB就是一种规范,谁要传输数据,就要实现这个规范
interface USB {
    //常量:比如usb长宽高、传输速率等
    void start();

    void stop();

}

// 设备Flash 具有USB功能
class Flash implements USB {
    @Override
    public void start() {
        System.out.println("Flash开始工作");
    }

    @Override
    public void stop() {
        System.out.println("Flash停止工作");
    }
}

// 设备打印机,具有USB功能
class Printer implements USB {

    @Override
    public void start() {
        System.out.println("打印机开始工作");
    }

    @Override
    public void stop() {
        System.out.println("打印机停止工作");
    }
}

/*
output:
打印机开始工作
usb中间操作
打印机停止工作
Flash开始工作
usb中间操作
Flash停止工作
*/

在这里插入图片描述
JDBC就是规范、接口,我只提供统一的抽象方法,调用哪个数据库对应实现那些方法;
在这里插入图片描述
接口应用:代理模式、工厂模式;

面试题
在这里插入图片描述


内部类
在这里插入图片描述
在这里插入图片描述
实例化内部类(静态和非静态)
在这里插入图片描述
局部内部类的使用:https://www.bilibili.com/video/BV1Kb411W75N?p=365


总结:
在这里插入图片描述
抽象类和接口的共同的和区别:
相同点:不能实例化,都可以被继承;
不同的:抽象类有构造器,接口不能声明构造器;


异常处理

错误:
在这里插入图片描述
异常:
在这里插入图片描述
异常分编译时异常和运行时异常;
在这里插入图片描述
异常体系结构:
在这里插入图片描述
运行时异常
ArrayIndexOutOfBoundsException
数据越界异常;
NullPointerException
空指针异常;
ClasscastException
ClassCastException是JVM在检测到两个类型间转换不兼容时引发的运行时异常;Java语言规范定义了允许的转换,其中大多数可在编译时进行验证。不过,某些转换还需要运行时验证。如果在此运行时验证过程中检测到不兼容,JVM就会引发ClassCastException异常;
NumberFormatException
数值类型格式异常;
在这里插入图片描述
InputMismatchException
输入不匹配异常,我要Int,结果输入的String;
在这里插入图片描述
ArithmeticException
算术异常,比如除0;

编译时异常
在编辑时,IDEA系统提示的错误其实就是编译的错误;


异常处理
如果用 if else 规避异常,则会显得臃肿不完善;
抛抓模型
①在异常处抛出异常类的对象;抛出后,其后代码不再执行;
②异常的处理方式,两种方式;

方式一:try-catch-finally
出现异常,自己有能力解决,直接干掉了,继续运行;
在这里插入图片描述
finally可选;
在这里插入图片描述
如果要得到异常详细信息,就输出e.getMessage() 或者 e.printStackTrace()

类似switch,但这里找到对应异常后,不执行别的catch了;
catch中的异常类型,如果不是父子关系,上下都无所谓,但如果是父子关系,就要求子类一定声明在父类上面,否则报错(后面的子类无法到达);

在try里面定义的变量,只能在里面用;

finally作用,针对catch中又出现了异常 或者 try、catch中的return语句放在finally中写比较好;
比如,像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动回收的,我们需要自己手动进行资源释放,此时就需要声明在finally中;

❗使用try-catch-finally处理编译时异常,使得程序在编译时就不再报错,但是运行时仍可能报错;
❗由于运行时异常比较常见,所以通常不针对运行时异常编写 try - catch - finally;

方式二:throws-异常类型
自己干不掉,让上一级处理,但总有一级需要去try catch 去处理这个异常;
在这里插入图片描述
注意点:
①子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型,就是子类抛比父类小的异常,父类才罩得住;
②如果父类被重写的方法没有throws方式处理异常,那么子类也不可以通过throws方式,则必须用try-catch;
③方法递进调用,最好用throws抛出再统一try-catch处理;

异常有系统生成,也有手动生成并抛出(throw);
throw new 异常类型(Message);这个message就是 getMessage() 方法返回的信息;
最好还是指定详细的异常类型,否则就还要throws一次;
在这里插入图片描述


自定义异常

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值