Java基础特性

Java基本概念

Java语言有哪些优点:

  1. Java为纯面向对象语言
  2. 平台无关性。Java为解释型语言,程序源代码经过Java编译器编译成字节码,然后由JVM解释执行。
  3. Java提供了很多内置的类库。提供了对多线程的支持,提供了对网络通信的支持,最重要的是提供了垃圾回收器。
  4. 提供了对Web应用开发的支持
  5. 具有较好的安全性和健壮性。安全性是指Java运行环境不允许Java程序访问当前浏览器上下文以外的内容。健壮性是指Java提供很多编译时的类型检查和异常处理。
  6. 去除了C++语言中难易理解,容易混淆的特性。例如头文件,指针

java和Go的区别

  1. 函数重载。

    Go上不允许函数重载,必须具有方法和函数的唯一名称。java允许函数重载。

  2. 多态。

    Java默认允许多态。而Go没有。

  3. 继承。

    Go语言的继承通过匿名组合完成:基类以Struct的方式定义,子类只需要把基类作为成员放在子类的定义中,支持多继承。

    Java的继承通过extends关键字完成,不支持多继承。

  4. 传递的值。

    java传递的值为栈中的值(值传递+引用传递)。其中:值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量. 引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。 所以对引用对象进行操作会同时改变原对象.一般认为,java内的传递都是值传递.

    go就是值传递,所以它是通过指针来完成引用传递

  5. 数组。

    Java中直接支持数组这种数据结构,除此之外还有通过数组结构延伸ArrayList.Class int[],String.Class 的char[] 等。 go 中也支持数组这种数据结构,因为是值传递,所以如何在其他方法中真实的修改数据呢 ,用指针或者Slice。go的指针不能运算。slice 在这方面就是一个数组的view, 但是他的具体结构类似ArrrayList.Class , 它有pre,len ,cap ,类似动态数组

ptr : 指定原来数组的首地址值
len : 目前slice的长度
cap : slice的容量 可指定或者是2的倍数

Java和 C/C++有什么异同

Java与C++都是面向对象语言,都使用了面向对象思想(封装,继承,多态)

不通点:

  1. Java为解释型语言,其运行过程为:Java为解释型语言,程序源代码经过Java编译器编译成字节码,然后由JVM解释执行。

    而C/C++为编译型语言,源代码经过编译和链接后生成可执行的二进制代码。 java执行速度比C/C++慢,但是java能够块平台,而C/C++不能

  2. Java为纯面向对象语言,所有代码(包括函数、变量等)必须在类中实现,

  3. 与C/C++语言相比,Java语言中没有指针的概念

  4. Java不支持多重继承,但是Java语言引入了接口的概念,可以同时实现多个接口。由于接口也具有多态特性,因此在Java语言中可以通过实现多个接口来实现与C++语言中多重继承类似的目的。

  5. Java语言提供了垃圾回收器来实现垃圾的自动回收,Java语言中虽然没有析构函数,但却引入了一个finalize()方法,当垃圾回收期将要释放无用对象的内存时,会首先调用该对象的finalize()方法,因此,开放人员不需要关心也不需要知道对象所占的内存空间何时会被释放。

什么是构造函数

Java中的clone方法有什么作用

Java中所有的类默认都继承自Object类,而Object类中提供了一个clone()方法。这个方法的作用是返回一个Object对象的复制。这个复制函数返回的是一个新的对象,而不是一个引用。

引申:浅复制和深复制有什么区别

浅复制:被复制对象的所有变量都含有与原来对象相同的值,而所有对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

深复制:被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制的新对象,而不再是原有的那些被引用的对象。换言之,深复制把复制的对象所引用的对象都复制了一遍。

JDK 与JRE的区别

  • Java运行时环境(JRE)。 它包括Java虚拟机、Java核心类库和支持文件。它不包含开发工具(JDK)--编译器、调试器和其他工具。
  • Java开发工具包(JDK)是完整的Java软件开发包,包含了JRE,编译器和其他的工具(比如:JavaDoc,Java调试器),可以让开发者开发、变异、执行Java应用程序。

面向对象技术

面向对象和面向过程有什么区别

面向对象的六个基本原则,迪米特法则,用过哪些

六个基本原则

  • 单一职责:一个类只做它该做的事情(高内聚)。在面向对象中,如果只让一个类完成它该做的事,而不设计与它无关的领域就是践行了高内聚的原则,这个类就只有单一职责。
  • 开放封闭:软件实体应当对扩展开放,对修改关闭。要做到开闭有两个要点。第一、抽象是关键,一个系统中如果没有抽象类或接口系统就没有扩展点;第二、封装可变性,将系统中的各种可变因素封装到一个继承结构中,如果多个可变因素混杂在一起,系统将变得复杂而混乱。

  • 里式替换:任何时候都可以用子类型替换掉父类型。子类一定是增加父类的能力而不是减少父类的能力,因为子类比父类的能力更多,把能力多的对象当成能力少的对象来用当然没有任何问题。

  • 依赖倒置:面向接口编程(该原则说得直白和具体一些就是声明方法的参数类型、方法的返回类型、变量的引用类型时,尽可能使用抽象类型而不用具体的类型,因为抽象类型可以被它的任何一个子类型所替代)。

  • 合成聚合复用:优先使用聚合或合成关系复用的代码。

  • 接口隔离:接口要小而专,绝不能大而全。臃肿的接口是对接口的污染。既然接口表示能力,那么一个接口只应该描述一种能力,接口也应该是高内聚的。

迪米特法则

迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。

项目中用到的原则

单一职责、开放封闭、合成聚合复用(最简单的例子就是String类)、接口隔离。

面向对象有哪些特征

  • 抽象 抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
  • 继承 子类不仅可以有父类的属性和方法,还可以有自己的属性和方法
  • 封装 将对象的属性进行私有化,只提供公共的get和set方法
  • 多态 允许不同子类型的对象对同一消息作出不同的响应。重载和重写

什么是继承

子类不仅可以有父类的属性和方法,还可以有自己的属性和方法

继承的好处

  • 子类能自动继承父类的接口
  • 创建子类的对象时,无须创建父类的对象

继承的坏处

  • 破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性
  • 支持扩展,但是往往以增加系统结构的复杂度为代价
  • 不支持动态集成。在运行时,子类无法选择不同的父类
  • 子类不能改变父类的接口

组合和继承有什么区别

多态的实现机制是什么

  • 方法重载(overload)实现的是编译时的多态性(也称为前绑定)
  • 方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西。
  • 要实现多态需要做两件事:1)方法重写(子类继承父类并重写父类中已有的或抽象的方法); 2)对象造型(用父类型引用子类型对象,这种通用的引用调用相同的方法就会根据子类对象的不同而表现出不同的行为)。

对象的多态

创建子类对象,并将次对象赋给父类的引用

虚拟方法调用(调用的是子类,且是子类重写父类的方法。要想调用子类独有的方法,先判断是否是子类实力,然后强制转换成子类,再调用)

编译时的多态,运行时的多态

多态前提:1.要有类的继承关系 2.子类要有方法的重写

项目中多对多态的应用

举一个简单的镊子,在信息管理系统中,有两种用户:采购和销售。两种用户都可以登录系统,他们有相同的方法login,但登录之后他们会进入到不同的页面,也就是在登录的时候会有不同的操作,两种客户都继承父类的login方法,但对于不同的对象,拥有不同的操作。

JDBC (一组规范:接口;不同的数据库厂商实现接口)

重载和覆盖有什么区别

重载和覆盖是Java多态性的不同表现方式。

  • 重载是在一个类中多态性的一种表现,是指一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型
  • 覆盖是指派生类函数覆盖基类函数。覆盖一个方法并对其重写,以达到不同的作用。

重载和覆盖的区别主要有以下几个方面:

  • 覆盖是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系。
  • 覆盖只能由一个方法或只能由一对方法产生关系;重载是多个方法之间的关系。
  • 覆盖要求参数列表相同;重载要求参数列表不同
  • 覆盖关系中,调用方法体是根据对象的类型(对象对应存储空间类型)来决定;而重载关系是根据调用时的实参表与形参表来选择方法体的。

重载(overload):

  1. 可以在一个类中也可以在继承关系的类中;
  2. 名相同;
  3. 参数列表不同(个数,顺序,类型)和方法的返回值类型无关。

重写(override)又名覆盖:

  1. 不能存在同一个类中,在继承或实现关系的类中;
  2. 名相同,参数列表相同,方法返回值相同;
  3. 子类方法的访问修饰符要大于父类的;(在父类中是public的方法,如果子类中将其降低访问权限为private,那么子类中重写以后的方法对于外部对象就不可访问了,这个就破坏了继承的含义)
  4. 子类的检查异常类型要小于父类的检查异常。(子类抛出更多的异常,会导致无法捕获Exception异常)

Java 中是否可以覆盖(override)一个 private 或者是 static 的方法?

  1. Java 中 static 方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而 static 方法 是编译时静态绑定的。static 方法跟类的任何实例都不相关,所以概念上不适用。
  2. java 中也不可以覆盖 private 的方法,因为 private 修饰的变量和方法只能在当前类中使用, 如果是其他的类继承当前类是不能访问到 private 变量或方法的,当然也不能覆盖。

抽象类(abstract class)与接口(interface)有什么异同

概念

抽象类:被abstract 修饰的类就是抽象类 如:abstract class Animal{ },抽象类的作用就是为了去让子类去继承它,提高代码重用性!

接口:我们可以把它看做是一种特殊的抽象类,接口中的所有方法都必须是抽象的,接口中的方法定义默认为 public abstract 类型,接口中的成员产量类型默认为 public static final。

相同点

  1. 都不能被实例化
  2. 可以将抽象类和接口类型作为引用类型
  3. 一个类如果实现接口或继承抽象类,必须实现全部抽象方法,否则仍然是个抽象类。

不同点版本一:

  1. 接口只有方法定义,没有具体的实现,实现接口的类要实现接口的所有方法;抽象类可以有定义与实现;
  2. 接口与类是实现关系,并且类可以多实现;抽象类与类是继承关系,只能被一个类继承。
  3. 接口中成员全为public, 抽象类中可以有抽象方法,也可以没有,抽象方法需加abstract
  4. 接口中无静态方法,抽象类中可以有。”
  5. 接口中不能定义构造器,抽象类中可以。

不同点版本二:

1、抽象类可以有构造方法,抽象方法和具体方法。

  接口不能有构造方法,而且其中的方法全部都是抽象方法。(接口中方法默认的是public abstract修饰的)

2、抽象类中的成员可以使private、默认、protected、public的。

  接口中的成员全部都是public的。

3、抽象类可以 定义成员变量。

  接口中定义的成员变量其实都是常量。(接口中的成员变量默认是public static final 修饰的 )

不同点版本三:

抽象类 接口
实现 子类使用extends关键字来继承抽象类 子类使用implements关键字来实现接口
构造器 抽象类中可以定义构造器 接口中不可以定义构造器
成员变量 抽象类中可以定义成员变量 接口中的成员变量其实就是常量,默认被public、static、final修饰
方法 可以有抽象方法和普通方法 可以有抽象方法(默认被public、abstract修饰)和普通方法(必须声明default修饰)
静态方法 抽象类中可以有静态方法 JDK1.8 以后可以有静态方法

什么时候使用

  1. 抽象类多用于在同类事物中有无法具体描述的方法的场景,所以当子类和父类之间存在有逻辑上的层次结构是,推荐使用抽象类。
  2. 接口多用于不同类之间,定义不同类之间的通信规则,所以当希望支持差别较大的两个或者更多对象之间的特定交互行为时,应该使用接口。

如何获取父类的类名

this与supper有什么区别

构造器中this调用本类的其他数据类型构造器,this(age)必须写到本构造器的首行

n个构造器,最多只含有n-1个含有this()的 ,否则编译时就会出错

不显示的调用本类或者父类的构造器,默认的调用父类的空参的构造器 super()

Java创建对象的四种方法

  1. 使用new关键字
  2. 使用 Class 类的 newInstance 方法,newInstance 方法调用无参的构造器创建对象(反射) Class.forName.newInstance
  3. 使用clone方法
  4. 反序列化

使用构造器的三种(new 和反射的两种 newInstance),没用构造器的两种(clone 和反序列化)

对对象的属性进行赋值

在哪些部分可以对对象的属性赋值(顺序):

  1. 声明的时候(默认初始化值)
  2. 显式的赋值或者在代码块中赋值
  3. 构造器
  4. 在方法中赋值

关键字

break、continue以及return有什么区别

final、finally和finalize有什么区别

final的好处

  1. final关键字提高了性能。JVM和Java应用都会缓存final变量。
  2. final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
  3. 使用final关键字,JVM会对方法、变量及类进行优化。

static关键字有哪些作用

static关键字主要有两种作用:第一,为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关。第二,实现某个方法或属性与类而不是对象关联在一起,也就是说,在不创建对象的情况下就可以通过类来直接调用方法或使用类的属性。

具体而言,在Java语言中,static主要有4种使用情况:成员变量,成员方法,代码块和内部类。

  1. static成员变量 静态变量随着类加载时被完成初始化,内存中只有一个,且JVN也只会为它分配一次内存,所有类共享静态变量。
  2. static成员方法 在类加载的时候就存在,不依赖任何实例;static方法必须实现,不能用abstract修饰。
  3. static代码块 在类加载完之后就会执行代码块中的内容。对static变量进行修改,静态中不能有非静态。static代码块 在类加载完之后就会执行代码块中的内容。对static变量进行修改,静态中不能有非静态。
  4. static内部类 父类静态代码块->子类静态代码块->父类非静态代码块->父类构造方法->子类非静态代码块->子类构造方法

在java语言中,不能再成员函数内部定义static变量

static 方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而 static 方法是编译 时静态绑定的。static 方法跟类的任何实例都不相关,所以概念上不适用。

volatile有什么作用

volatile是一个类型修饰符,它是被用来修饰被不同线程访问和修改的变量。被volatile类型定义的变量,系统每次用到它时都是直接从对应的内存当中提取,而不会利用缓存,在使用了volatile修饰成员变量后,所有线程在任何时候所看到的变量的值都是相同的。

instanceof有什么作用

strictfp有什么作用

关键字strictfp是strict float point 的缩写,指的是精确浮点,它用来确保浮点数运算的准确性。

基本类型与运算

Java提供了哪些基本数据类型

8种基本数据类型 boolean,byte ,short, int ,long ,char , float,double

封装类型: Boolean,Byte ,Short,Integer,Long,Character,Float,Double

什么是不可变类

值传递与引用传递有哪些区别

(1)值传递: 在方法调用中,实参会把它的值传递给形参,形参只是用实参的值初始化一个临时的存储单元,因此形参与实参虽然有着相同的值,但是却有着不同的存储单元,因此对形参的改变不会影响实参的值。

(2)引用传递:在方法调用中,传递的是对象(也可以看作是对象的地址),这时形参与实参的对象所指向同一块存储单元,因此对形参的修改就会影响实参的值。

在java语言中,基本数据类型在床底参数是都是按值传递,而包装类型在传递参数时是按引用传递。

  • 从概念方面来说
    • 基本类型:变量名指向具体的数值。
    • 引用类型:变量名指向内存数据对象的内存地址
  • 从内存方面来说
    • 基本类型:变量在声明之后,Java就会立即分配给他内存空间
    • 引用类型:它以特殊的方式(类似C指针)向对象实体(具体的值),这类变量声明时不会分配内存,只是存储了一个内存地址
  • 从使用方面来说
    • 基本类型:使用时需要赋具体值,判断时使用==号。
    • 引用类型:使用时可以赋null,判断时使用equals方法。

:point_right: 扩展阅读:Java 基本数据类型和引用类型

这篇文章对于基本数据类型和引用类型的内存存储讲述比较生动。

String转出int型,判断能不能转?如何转

可以转,得处理异常Integer.parseInt(s) 主要为NumberFormatException:1)当你输入为字母时,也就是内容不是数字时,如abcd ;2)当你输入为空是;3)当你输入超出int上限时

Long.parseLong("123")转换为long

short s1=1;s1=s1+1;有什么错?

  • 对于short s1=1;s1=s1+1;来说,在s1+1运算时会自动提升表达式的类型为int,那么将int赋予给short类型的变量s1会出现类型转换错误
  • 对于short s1=1;s1+=1;来说,+=是java语言规定的运算符,java编译器会对它进行特殊处理。在解析时候s+=1就等价于s = (short)(s+1)。s=s+1这句先执行s+1然后把结果赋给s,由于1为int类型,所以s+1的返回值是int,编译器自动进行了隐式类型转换

Math类中round、ceil和floor方法的功能各是什么

字符串与数组

字节与字符区别

字节是存储容量的基本单位,字符是数字、字母、汉字一起其他语言的各种符号。

1字节=8个二进制单位,一个字符由一个字节或多个字节的二进制单位组成。

字符串创建与存储的机制是什么

“==”、equals和hashCode有什么区别

(1) "=="运算符用来比较两个变量的值是否相等。也就是说,该运算符用于比较变量对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能使用“==”运算符。

(2)equals是Object类提供的方法之一。每一个Java类都继承自Object类,所以每一个对象都具有equals这个方法。Object类中定义的equlas(Object)方法是直接使用“==”运算符比较的两个对象,所以在没有覆盖equlas(Object)方法的情况下,equlas(Object)与“==”运算符一样,比较的是引用。

​ 相比“==”运算符,equlas(Object)方法的特殊之处就在于它可以被覆盖,所以可以通过覆盖的方法让它不是比较引用而是比较数据内容,例如String类的equlas方法是用于比较两个独立对象的内容是否相同,即堆中的内容是否相同。

​ 如果一个类没有自己定义equlas()方法,它默认的equal()方法(从Object类继承的)就是使用"=="运算符,也是在比较两个变量指向的对象是否是同一对象,此时使用equlas()方法和使用“==”运算符会得到相同的结果。若比较的是两个独立的对象,则总返回false。如果编写的类希望能够比较该类创建的两个实例对象的内容是否相同,那么必须覆盖equlas()方法。由开发人员自己编写代码来决定在什么情况下即可认为连个对象的内容是相同的。

(3)hashCode()方法是从Object类中继承过来的,它也用来鉴定两个对象是否相等。Object类中的hashCode()方法返回对象在内存中地址转换成的一个int值,所以如果没有重写hashCode()方法,任何对象的hashCode()方法都是不想等的。

​ hashCode()方法的返回值和equals()方法的关系如下:

​ 如果x.equals(y)返回true,即两个对象根据equals方法比较是相等的,那么调用者两个对象中任意一个对象的hashCode()方法都必须产生同样的整数结果。如果x.equals(y)返回false,即两个对象根据equals()方法比较是不相等的,那么x和y的hashCode()方法的返回值有可能相等,也有可能不相等。

反之,hashCode()方法的返回值不相等,一等能推出equals()方法的返回值也不相等,而hashCode()方法的返回值相等,equals()方法的返回值则可能相等,也可能不相等。

请你解释为什么重写equals还要重写hashcode?

HashMap中,如果要比较key是否相等,要同时使用这两个函数!

因为自定义的类的hashcode()方法继承于Object类,其hashcode码为默认的内存地址,这样即便有相同含义的两个对象,比较也是不相等的。HashMap中的比较key是这样的,先求出key的hashcode(),比较其值是否相等,若相等再比较equals(),若相等则认为他们是相等的。若equals()不相等则认为他们不相等。如果只重写hashcode()不重写equals()方法,当比较equals()时只是看他们是否为同一对象(即进行内存地址的比较),所以必定要两个方法一起重写。HashMap用来判断key是否相等的方法,其实是调用了HashSet判断加入元素 是否相等。重载hashCode()是为了对同一个key,能得到相同的Hash Code,这样HashMap就可以定位到我们指定的key上。重载equals()是为了向HashMap表明当前对象和key上所保存的对象是相等的,这样我们才真正地获得了这个key所对应的这个键值对。

  • 当equals方法被重写是,通常有必要重写hashCode方法,以维护hashCode方法的常规协定,该协定声明相对等的两个对象必须有相同的hashCode

    object1.equal(object2)时为true,object1.hashCode() == object2.hashCode() 为true

    object1.hashCode() == object2.hashCode()为false时,object1.equal(object2)必定为false

    object1.hashCode() == object2.hashCode()为true时,但object1.equal(object2)不一定为true

  • 重写equals不重写hashcode会出现什么问题

    在存储散列集合是(如Set类),如果原对象.equals(新对象),但没有对hashCode重写,即两个对象拥有不同的hashCode,则在集合中将会存储两个值相同的对象,从而导致混淆。因此在重写equals方法是,必须重写hashCode方法

怎么处理构造相同hash的字符串进行攻击

  • 当客户端提交一个请求并附带参数的时候,web应用服务器会把我们的参数转化成一个HashMao存储,这个HashMap的逻辑结构如下:key1-->value;

  • 但是物理存储结构是不同的,key值会被转化成hashcode,这个hashcode又会被转成数组的下标:0-->value1;

  • 不同的string就会产生相同hashcode而导致碰撞,碰撞后的物理存储结构可能如下:0-->value1-->value2;

    1. 限制post和get的参数个数,越少越好
    2. 限制post数据包的大小
    3. WAF
  • jdk7 如何处理hashcode字符串攻击

    HashMap会动态的使用一个专门的treemap实现来替换掉它

String不可变?

String不变性的理解

  • String 类是被final进行修饰的,不能被继承
  • 在用+号链接字符串的时候会创建新的字符串
  • String s = new String("Hello world"); 可能创建两个对象,如果静态区中有"Hello world"字符串常量对象的话,则仅仅在堆中创建一个对象。如果静态区中没有"Hello world"对象,则堆上和静态区中都需要创建对象。
  • 在java中,通过使用"+"符号来串联字符串的时候,实际上底层会转成通过StringBuilder实例的append()方法来实现。

final

  • 首先因为String不可变,如果String不是final,那么就可以有子类继承String类,然后子类覆盖其方法,使得这些方法可以修改字符串,这样就违背了String的不可变性

不可变原因

  • 提高效率:比如一个字符串String s1="abc","abc"被放到常量池里面去了,我再String s2="abc"并不会复制字符串"abc",只会多个引用指向原来那个常量,这样就提高了效率,而这一前提是String不可变,如果可变,那么多个引用指向同一个字符串常量,我就可以通过一个引用改变字符串,然后其他引用就被影响了
  • 安全:String常被用来表示url、文件路径,如果String可变,或存在安全隐患
  • String不可变,那么它的hashcode就一样,不用每次重新计算了。

String有重写Object的hashcode的toString吗?

重写了

String、StringBuffer、StringBuilder和StringTokenizer有什么区别

  • String: 如果要操作的数据量比较小,应优先使用String类
  • StringBuilder:如果是在单线程下操作大量数据,应优先使用StringBuilder。(效率最高)
  • StringBuffer: 如果是在多线程下操作大量数据,应优先使用StringBuffer。(线程安全)在一个字符串需要经常被修改时使用。
  • StringTokenizer类拆分字符串。官方推荐使用split进行字符串拆分,split可以匹配正则表达式,而StringTokenizer则不行。

Java中数组是不是对象

length属性与length()方法有什么区别

在java语言中,

  • 数组提供了length属性来获取数组的长度
  • length()方法是针对字符串而言的
  • size()方法是针对泛型集合而言的,用于查看泛型中有多少个元素

异常处理

java中如何描述问题Throwable(顶级父类)

  1. 错误Error (虚拟机爆出来的错误) 内存溢出 StackOverflowError

  2. 异常Exception

    (受检异常 非受检异常 )

    (运行时异常,非运行时异常)

有个Throwable的层次体系

常见的异常

  • 常见运行时异常

空指针异常:java.lang.NullPointerException

数组下标越界异常:java.lang.ArrayIndexOutOfBoundsException

数学异常:java.lang.ArithmeticException

类型转换异常:java.lang.ClassCastException

  • 常见非运行时异常IO异常

找不到文件异常:java.io.FileNotFoundException

反射异常找不到类异常:java.lang.ClassNotFoundException

  • 运行时异常和非运行时异常的区别

    <1>运行时异常在编译期间不要求强制处理

    <2>非运行时异常在编译器件要求强制处理

异常处理机制

处理异常的核心机制抓抛模型

异常的抛出

throws关键字:

以类名的方式,在方法名后面声明该方法有可能抛出的异常,告诉调用者使用该方法存在的风险如果方法体内会抛出非运行时异常,那么在方法名后面所声明的异常类列表中,必须包含那个方法体内的异常类或其父类如果在方法中调用一个声明抛出非运行时异常的方法,那么在当前方法中就必须该异常进行处理,要么捕获,要么继续声明抛出

throw关键字:

在方法体内显示抛出一个异常类对象。这个对象可以是使用new关键字创建的已经存在的异常类的实例对象,也可以是自定义异常类的实例对象,甚至可以是catch块中捕获的异常对象,但通常用来抛出自定义异常手动抛出非运行时异常类对象程序代码中必须进行处理,要么抛给调用者,要么进行捕获手动抛出运行时异常类对象,JDK不要求显示处理

抛出

在方法中,将一个已经生成的异常对象“抛”给它的调用者方法处理。此时调用者方法如果还不处理,可以继续向上抛。如果当前方法已经是main()方法,那么异常对象将会交给Java运行时系统处理,这种情况下,异常对象是被Java虚拟机捕获的。抛出通常表示不处理,交给调用者处理

捕获

这里指程序开发人员对异常情况的处理。在方法中,对运行中可能出现的异常对象预先设定好“捕获”的方式,即捕获异常的代码。捕获后通常可以对异常情况进行有针对性的处理,补救或挽回。

自定义异常

方式:继承已有的异常类

  • 继承RuntimeException:可以按处理运行时异常的方式进行处理,推荐使用这种方式
  • 继承Exception:必须按处理非运行时异常的方式进行处理,通常不采用

results matching ""

    No results matching ""