Java学习
java入门学习当你们还在打完一局王者的时候,我就已经开始入门java了哈哈哈哈哈哈
这是好久之前总结的了,先试着发一发吧。
1.类变量
类变量也称为静态变量
静态变量随着类的创建而创建,所有的对象共享静态方法区,可通过对象调用也可直接通过类调用
特点:
- static变量是同一个类所有对象共享。
- static类变量,在类加载的时候就生成了,因此可以不用创建对象再来使用。
public class StaticMethod {
public static void main(String[] args) {
Stu tom = new Stu("tom");
Stu.payFee(100);//通过类名来调用静态类变量
Stu jack = new Stu("jack");
Stu.payFee(200);//通过对象来调用
Stu.showFee();
}
}
class Stu{
private String name;//普通成员
private static double fee = 0;//静态变量
public Stu(String name) {
this.name = name;
}
//说明
public static void payFee(double fee){
Stu.fee += fee;
}
public static void showFee(){
System.out.println("总学费为:"+Stu.fee);
}
}
类变量注意点
class D{
private static int n1 = 100;
public void say(){
//可以使用this,super
//普通成员方法既可以访问非静态成员,也可以访问静态成员
System.out.println(this.n1);
}
public static void hi(){
//类方法(静态方法)不可使用this,super和对象相关的关键字
//静态方法只能访问静态成员
System.out.println(n1);
hi();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nLTMhaSt-1665747352537)(E:\学习笔记\图片\未命名文件 (2)].png)
2.代码块
- 对构造器进行完善,多个构造器有重复的语句可以写在代码块,提高代码的重用性
- 在构造器使用时会优先调用代码块中的内容
public class CodeBlock01 {
public static void main(String[] args) {
Movie movie = new Movie("你好,李焕英",100,"贾玲");
}
}
class Movie{
private String name;
private double price;
private String director;
//code block
{
System.out.println("Movie scree is opening...");
System.out.println("advertisement is beginning....");
System.out.println("Movie is starting...");
}
//构造器
//In this way what kinds of constructor we call,we must first call the code block message
public Movie(String name) {
this.name = name;
}
public Movie(String name, double price) {
this.name = name;
this.price = price;
}
public Movie(String name, double price, String director) {
this.name = name;
this.price = price;
this.director = director;
}
}
1.静态代码块
对类进行初始化,而且它随着类的加载而执行,并且只会执行一次,如果是普通代码块,每创建一个对象,就执行一次
类什么时候被加载!!!
- 创建对象实例的时候
- 创建子类对象实例,父类也会加载,而且父类先被加载,子类后被加载
- 使用类的静态成员的时候(静态属性,静态方法)
普通代码块,在创建对象实例时,会被隐式的调用,被创建一次就会调用一次
如果只是使用类的静态成员时,普通代码块不会执行
public class CodeBlockDetail01 {
public static void main(String[] args) {
//类被加载的情况实例
//创建对象实例的时候
//AA aa1 = new AA();
// 2.创建子类对象实例,父类也会加载
//AA aa2 = new AA();
// 3.使用类的静态成员的时候(静态属性,静态方法)
System.out.println(Cat.n1);
}
}
class BB{
static {
System.out.println("BB 的静态代码1被执行。。。");
}
}
class AA extends BB{
//静态代码块
static {
System.out.println("AA 的静态代码1被执行。。。");
}
}
class Cat{
public static int n1 = 999;
static {
System.out.println("Cat 的静态代码1被执行。。。");
}
}
创建一个类时,在一个类的调用顺序:
1.调用静态代码块和静态属性初始化
静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用
public class CodeBlockDetail02 {
public static void main(String[] args) {
A a = new A();//会先输出getN1被调用 然后输出A 静态代码块01
}
}
class A{
//静态属性初始化
private static int n1 =getN1();
static {
System.out.println("A 静态代码块01");
}
public static int getN1(){
System.out.println("getN1被调用");
return 100;
}
}
- 静态属性和静态代码块的优先级一样因为 属性在静态代码块前就被调用,所以先调用getN1,后调用静态代码块
2.调用普通代码块和普通属性的初始化
普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化按定义顺序调用
public class CodeBlockDetail02 {
public static void main(String[] args) {
A a = new A();
}
}
class A{
private int n2 = getN2();
//静态属性初始化
private static int n1 =getN1();
{
System.out.println("普通代码块");
}
static {
System.out.println("A 静态代码块01");
}
public static int getN1(){
System.out.println("getN1被调用");
return 100;
}
public int getN2(){
System.out.println("getN2被调用");
return 200;
}
//结果为:
getN1被调用
A 静态代码块01
getN2被调用
普通代码块
3.调用构造方法
public class CodeBlockDetail02 {
public static void main(String[] args) {
A a = new A(3);
}
}
class A{
private int n2 = getN2();
//静态属性初始化
private static int n1 =getN1();
{
System.out.println("普通代码块");
}
static {
System.out.println("A 静态代码块01");
}
public static int getN1(){
System.out.println("getN1被调用");
return 100;
}
public int getN2(){
System.out.println("getN2被调用");
return 200;
}
public A(int n2) {
System.out.println("A()构造器被调用");
this.n2 = n2;
}
}
//结果:
getN1被调用
A 静态代码块01
getN2被调用
普通代码块
A()构造器被调用
2.普通代码块
调用顺序: 父类代码块->父类构造器->子类代码块->子类构造器
public class CodeBlockDetail03 {
public static void main(String[] args) {
new BBB();
}
}
class AAA {
{
System.out.println("这是AAA的代码块");
}
public AAA(){
System.out.println("AAA构造器被调用");
}
}
class BBB extends AAA{
{
System.out.println("这是BBB的代码块");
}
public BBB(){
System.out.println("BBB构造器被调用");
}
}
结果:
这是AAA的代码块
AAA构造器被调用
这是BBB的代码块
BBB构造器被调用
3.静态代码块和普通代码块
执行顺序:父类静态->子类静态->父类普通(代码块和属性)->父类构造方法->子类普通(代码块和属性)->子类构造方法
3.单例设计模式
单例(单个实例)
使用单例模式能够保证整个应用中有且只有一个实例。解决问题的关键就是保证在应用中只有一个对象就行了,
其实只需要三步就可以保证对象的唯一性
(1)不允许其他程序用new对象。
因为new就是开辟新的空间,在这里更改数据只是更改的所创建的对象的数据,如果可以new的话,每一次new都产生一个对象,这样肯定保证不了对象的唯一性。
(2)在该类中创建对象
因为不允许其他程序new对象,所以这里的对象需要在本类中new出来
(3)对外提供一个可以让其他程序获取该对象的方法
因为对象是在本类中创建的,所以需要提供一个方法让其它的类获取这个对象。
那么这三步怎么用代码实现呢?将上述三步转换成代码描述是这样的
(1)私有化该类的构造函数(防止用户直接new)
(2)通过new在本类中创建一个本类对象
(3)定义一个公有的方法,将在该类中所创建的对象返回。getinstance
(4)代码实现
1.饿汉式单例模式
public class SingleTon01 {
public static void main(String[] args) {
GirlFriend instance = GirlFriend.getInstance();
System.out.println(instance);
GirlFriend instance1 = GirlFriend.getInstance();
System.out.println(instance1);
System.out.println(instance == instance1);//判断对象是否是同一个
}
}
class GirlFriend {
private String name;
//2.在类的内部直接创建对象(该对象是static的)
//饿汉模式可能造成创建了对象但是没有使用
private static GirlFriend gf = new GirlFriend("小红");
//1.私有化该类的构造函数
private GirlFriend(String name){
System.out.println("构造器被调用");
this.name = name;
}
//3.提供一个公共的static方法,返回gf对象
public static GirlFriend getInstance(){
return gf;
}
@Override
public String toString() {
return "GirlFriend{" +
"name='" + name + '\'' +
'}';
}
}
结果:
构造器被调用
GirlFriend{name='小红'}
GirlFriend{name='小红'}
true
//构造器在类加载时不被调用在创建对象时被调用
2.懒汉式单例模式
public class SingleTon02 {
public static void main(String[] args) {
// new Cat();
// System.out.println(Cat.n1);
Cat instance = Cat.getInstance();
System.out.println(instance);
//再次调用
Cat instance2 = Cat.getInstance();
System.out.println(instance2);
//判断对象是否是同一个
System.out.println(instance == instance2);
}
}
//懒汉式,只有当用户使用getinstance时,才返回cat对象,后面再次调用时,返回上次的对象,从而保证了单例
//希望在程序运行的过程中,只能创建一个Cat对象
class Cat{
private String name;
public static int n1 = 999;
//2.在类的内部定义对象(该对象是static的)
private static Cat cat = null;
//步骤
//1.私有化该类的构造函数
private Cat(String name){
System.out.println("构造器调用");
this.name = name;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
//3.提供一个公共的static方法,返回gf对象
//在此处有线程安全问题(同时有多个线程访问单例模式会被破坏)
public static Cat getInstance(){
if(cat == null){//如果没有创建cat对象
cat = new Cat("大黄");
}
return cat;
}
}
构造器调用
Cat{name='大黄'}
Cat{name='大黄'}
true
//构造器在类加载时不被调用在创建对象时被调用
饿汉式和懒汉式的区别
1.二者最主要的区别是创建对象的时机不同:饿汉式是在类加载就创建了对象实例,懒汉式是在使用时创建
2.饿汉式不存在线程安全问题,懒汉式存在线程安全问题
3.饿汉式存在资源浪费问题
4.final关键字
用于修饰类、成员变量和成员方法,final修饰的类,不能被继承,其中所有的方法都不能被重写(不能被重写,但是可以被重载)Final修饰的方法不能被重写,但是子类可以用父类中final修饰的方法;
重写:
1.发生在父类与子类之间
2.方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同
3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
4.重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常重载:
1.重载Overload是一个类中多态性的一种表现
2.重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序)
3.重载的时候,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准
深入理解一下被final修饰的类、方法、变量
1.final修饰的类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uTYUdoz5-1665747352540)(E:\学习笔记\图片\22-4-22.jpg)]
final修饰的类不能够被继承
2.final修饰的变量
public final class Final01 {
public static void main(String[] args) {
String a = "xiaomeng2";
final String b = "xiaomeng";
String d = "xiaomeng";
String c = b + 2;
String e = d + 2;
System.out.println((a == c));
System.out.println((a == e));
}
//
true
false
b 是 final 修饰的,变量 b 的值在编译时候就已经确定了它的确定值,换句话说就是提前知道了变量 b 的内容到底是个啥,相当于一个编译期常量;
b 是一个常量,所以在使用 b 的时候直接相当于使用 b 的原始值(xiaomeng)来进行计算,所以 c 生成的也是一个常量,a 是常量,c 也是常量,都是 xiaomeng2 而 Java 中常量池中只生成唯一的一个 xiaomeng2 字符串,所以 a 和 c 是相等的!
a和c指向常量池中的xiaomeng2,
e的话由于使用的是 d 的引用计算,变量d的访问却需要在运行时通过链接来进行,所以这种计算会在堆上生成 xiaomeng2 ,e指向堆中的xiaomeng2
final修饰引用变量和基本变量有什么不同
基本变量:基本变量在被final修饰后就不可以改变
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-01xHWmtM-1665747352541)(E:\学习笔记\图片\Snipaste_2022-04-22_19-02-32.jpg)]
引用变量:基本变量在被final修饰后就不可以改变,但引用对象的内容可以改变
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZWKyQBBW-1665747352541)(E:\学习笔记\图片\Snipaste_2022-04-22_19-09-24.jpg)]
使用final修饰了的类不能再指向别处
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sGxhvVhO-1665747352542)(E:\学习笔记\图片\Snipaste_2022-04-22_19-05-07.jpg)]
final关键字的好处:
- final方法比非final快一些
- final关键字提高了性能。JVM和Java应用都会缓存final变量。
- final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
- 使用final关键字,JVM会对方法、变量及类进行优化。
3.final使用细节
- final修饰的属性又叫常量,一般用XX_XX(大写字母)来命名
- final修饰的属性在定义时必须赋初值,并且以后不能再更改赋值可以在以下位置进行
- 在定义时
- 在构造器中
- 在代码块中
class AA{
public final double TAX_RATE = 0.08;//在定义时
public final double TAX_RATE2;//在构造器中
public final double TAX_RATE3;//在代码块中
public AA(){
TAX_RATE2 = 1.1;
}
{
TAX_RATE3 = 3.3;
}
}
3.如果final修饰的属性是静态的,则初始化的位置只能是:(1)定义时(2)在静态代码块 (3)不能在构造器中赋值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FlSj9eBd-1665747352543)(E:\学习笔记\图片\Snipaste_2022-04-23_20-15-27.jpg)]
- 构造器在创建对象的时候才会被调用,而静态变量的初始化在类加载时就要给出值
4.final类不能继承但是可以实例化对象
public final class Final01 {
public static void main(String[] args) {
new CC();//实例化
}
}
final class CC{}
5.如果不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承
public static void main(String[] args) {
new CC();
EE ee = new EE();
ee.cal();//cal()方法被继承
}
}
class DD{
public final void cal(String[] args) {
System.out.println("cal()方法");
}
}
class EE extends DD{
}
(了解即可)
6.一般来说,如果一个类已经是final类了,就没必要将方法修饰成final方法
7.final不能修饰构造器
8.final和static往往搭配使用,效率更高,底层编译器做了优化(不会导致类加载)
9.包装类(Integer,Double,Float,Boolean等都是final),string也是final类
5.抽象类
引论:为什么要有抽象类
class Animal{
private String name;
public Animal(String name) {
this.name = name;
}
//这里eat方法 实现了但是没有意义
//即:父类方法不确定性
//===》 考虑将其写为抽象(abstract)方法
//==》 一般来说抽象类会被继承,由其子类来实现抽象方法
public void eat(){
System.out.println("这是一个动物,但是不知道吃什么");
}
}
所有的普通方法上面都会有一个“{}”,这个表示方法体,有方法体的方法一定可以被对象直接使用。而抽象方法,是指没有方法体的方法,同时抽象方法还必须使用关键字abstract做修饰。
public class AbstractDemo01 {
}
abstract class A{//定义一个抽象类
public void fun(){//普通方法
System.out.println("存在具体的方法");
}
public abstract void print();//抽象方法,没有方法体,有abstract关键字
}
1.抽象类细节
- 抽象类不能被实例化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qVUtVRuH-1665747352543)(E:\学习笔记\图片\Snipaste_2022-04-23_21-02-12.jpg)]
2.抽象类不一定要包含abstract方法。
3.一旦类包含了抽象方法则类必须是抽象类
4.abstract只能修饰类和方法,不能修饰属性和其他的
5.抽象类可以有任意成员[抽象类的本质还是类]
6.抽象方法不能有主体(方法体),不能实现
7.如果一个类继承了抽象类,则他必须实现抽象类的所有方法,除非他本身也是抽象类
public class AbstractDetail01 {
public static void main(String[] args) {
new B().hi();
}
}
abstract class A{
public abstract void hi();
}
class B extends A{
@Override
public void hi() {
System.out.println("hi");
}
8.抽象方法不能使用private、final和static来修饰,因为这些关键字都不允许重写
2.抽象类的最佳实践-模板设计模式
提高代码的复用性
abstract public class Tamplate {//抽象类-模板设计模式
public abstract void job();
public void calculateTime(){//调用了job方法
//得到开始时间
long start = System.currentTimeMillis();
job();
//得到结束时间
long end = System.currentTimeMillis();
System.out.println("AA执行时间"+(end - start));
}
}
public class AA extends Tamplate{
@Override
public void job(){
long num = 0;
for (int i = 0; i < 800000; i++) {
num +=i;
}
}
}
public class BB extends Tamplate{
@Override
public void job(){
long num = 0;
for (int i = 0; i < 800000; i++) {
num *= i;
}
}
}
public class Test {
public static void main(String[] args) {
AA aa = new AA();
aa.calculateTime();
BB bb = new BB();
bb.calculateTime();
}
}
6.接口
usb插槽就是现实中的接口
1.入门
定义接口
public interface Usbinterface {//接口
//规定接口的相关方法
public void start();
public void stop();
}
实现接口
//Phone类 实现 Usbinterface
//1.即phone类需要实现 usbinterface接口 规定/声明方法
public class Phone implements Usbinterface {
@Override
public void start() {
System.out.println("手机开始工作");
}
@Override
public void stop(){
System.out.println("手机停止工作");
}
}
public class Camera implements Usbinterface{
@Override
public void start() {
System.out.println("相机开始工作");
}
@Override
public void stop() {
System.out.println("相机停止工作");
}
}
调用接口
public class Computer {
//编写一个方法
public void work(Usbinterface usbinterface){
//规定接口相关方法,定义了规范
//通过接口来调用方法
usbinterface.start();
usbinterface.stop();
}
}
public class Interface01 {
public static void main(String[] args) {
//创建手机,相机对象
Phone phone = new Phone();
Camera camera =new Camera();
//创建计算机
Computer computer = new Computer();
computer.work(phone);//把手机接入到计算机
System.out.println("============");
computer.work(camera);//把相机接入到计算机
}
}
结果:
手机开始工作
手机停止工作
============
相机开始工作
相机停止工作
由上面的例子可以得出接口就是一些没有实现的的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来
- 接口是更加抽象的抽象类,抽象类的方法可以有方法体,接口里所有的方法都没有方法体
- 接口体现了程序设计的多态和高内聚低耦合的设计思想
jdk8.0后接口类可以有静态方法,默认方法,也就是说接口中可以有方法体的具体实现
public interface AInterface {
//写属性
public int n1 = 10;
//写方法
//在接口中,抽象方法可以省略abstract关键字
public void hi();
//在jdk8后,可以有默认实现方法,需要使用default关键字修饰
default public void ok(){
System.out.println("ok.......");
}
//在jdk8后,可以有静态方法
public static void cry(){
System.out.println("cry......");
}
}
2.什么时候使用接口
项目经理开发一个软件,为了控制和管理软件,项目经理可以定义一些接口,然后由程序员具体实现
可以使命名更加规范
接口
public interface DBInterface {//项目经理
public void connect();//连接方法
public void close();//关闭方法
}
//A程序员连接Mysql
public class MysqlDB implements DBInterface{
@Override
public void connect() {
System.out.println("连接mysql");
}
@Override
public void close() {
System.out.println("关闭mysql");
}
}
//B程序员连接Oracle
public class OracleDB implements DBInterface{
@Override
public void connect() {
System.out.println("连接Oracle");
}
@Override
public void close() {
System.out.println("关闭Oracle");
}
}
public class Interface03 {
public static void main(String[] args) {
MysqlDB mysqlDB = new MysqlDB();
t(mysqlDB);
}
public static void t(DBInterface db){
db.connect();
db.close();
}
//结果
连接mysql
关闭mysql
3.接口的使用细节
- 接口不能被实例化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x420XgQM-1665747352544)(E:\学习笔记\图片\Snipaste_2022-04-24_00-17-56.jpg)]
2.接口中的方法是public方法,接口中抽象方法,可以不用abstract修饰
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fao8ZEqa-1665747352544)(E:\学习笔记\图片\Snipaste_2022-04-24_00-35-29.jpg)]
3.一个普通类实现接口,就必须将该接口的所有方法都实现,可以使用快捷键alt+enter来实现
4.抽象类实现接口可以不用实现接口方法
5.一个类同时可以实现多个接口
interface IB {
void hi();
}
interface IC{
void say();
}
//一个类可以实现多个接口
class Pig implements IB,IC{
@Override
public void hi() {
}
@Override
public void say() {
}
}
6.接口中的属性,只能是final的,而且是public static final修饰符,比如int a = 1;实际上是public static final int a = 1;(必须初始化)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Rg5vXqK-1665747352545)(E:\学习笔记\图片\Snipaste_2022-04-24_00-53-46.jpg)]
7.接口中属性的访问:接口名.属性名
8.接口不能继承其他的类,但是可以继承多个别的接口
interface IB {
int n1 =10;
void hi();
}
interface IC extends{
void say();
}
//接口不能继承其他的类,但是可以继承多个别的接口
interface ID extends IB,IC{
}
9.接口的修饰符 只能是public和默认,这一点和类修饰符一样
4.实现接口和继承类的区别
- 继承只能继承父类的方法(单继承)
public class ExtendsVsInterface {
public static void main(String[] args) {
LittleMonkey littleMonkey= new LittleMonkey("悟空");
littleMonkey.climbing();
}
}
//猴子
class Monkey{
private String name;
public Monkey(String name) {
this.name = name;
}
public void climbing(){
System.out.println(name+"会爬树");
}
}
class LittleMonkey extends Monkey{
public LittleMonkey(String name) {
super(name);
}
}
- 接口可以实现多种实现方法
//接口
interface Fishable{
void swimming();
}
interface Birdable{
void flying();
}
//实现接口
class LittleMonkey extends Monkey implements Fishable,Birdable{
public LittleMonkey(String name) {
super(name);
}
@Override
public void swimming() {
System.out.println(getName()+"通过学习学会了游泳");
}
@Override
public void flying() {
System.out.println(getName()+"通过学习学会了飞翔");
}
}
//调用
public static void main(String[] args) {
LittleMonkey littleMonkey= new LittleMonkey("悟空");
littleMonkey.climbing();
littleMonkey.swimming();
littleMonkey.flying();
}
- 接口和继承解决的问题不同
继承的价值主要在于:解决代码的复用性和可维护性
接口的价值主要在于:设计好各种规范,让其他类去实现这些方法,即更加的灵活
- 接口在一定程度上实现代码的解耦[即:接口规范性+动态绑定]
5.接口的多态性
多态参数
public class InterfacePolyParameter {
public static void main(String[] args) {
//接口的多态体现
//接口类型变量 if01可以指向实现了if接口类的对象实例
IF if01 = new Monster();
if01 = new Car();
//继承实现多态
//父类类型的变量 a 可以指向继承AAA的子类的对象实例
AAA aaa = new BBB();
aaa = new CCC();
}
}
interface IF{}
class Monster implements IF{}
class Car implements IF{}
class AAA{}
class BBB extends AAA{}
class CCC extends AAA{}
多态数组
public static void main(String[] args) {
//多态数组 ->接口类型数组
Usb[] usb = new Usb[2];
usb[0] = new Phone_();//存放phone_类型
usb[1] = new Camera_();//存放camera_类型
for (int i = 0;i<usb.length;i++){
usb[i].work();
//进行类型的向下转型
if (usb[i] instanceof Phone_){
((Phone_) usb[i]).call();//强制转换
}
}
}
}
interface Usb{
public void work();
}
class Phone_ implements Usb{
public void call(){
System.out.println("手机可以打电话");
}
@Override
public void work() {
System.out.println("手机工作中");
}
}
class Camera_ implements Usb{
@Override
public void work() {
System.out.println("相机工作中");
}
}
多态传递
public class InterfacePolyPass {
public static void main(String[] args) {
IG ig = new Teacher();
//如果IG继承了IH接口,而Teacher类实现了IG接口
//Teacher也得实现IH接口
IH ih = new Teacher();
}
}
interface IH{
void hi();
}
interface IG extends IH{}
class Teacher implements IG{
@Override
public void hi() {
}
}
小练习
public class InterfaceExperience {
public static void main(String[] args) {
}
}
interface A {
int x = 0;
} //想到 等价 public static final int x = 0;
class B {
int x = 1;
} //普通属性
class C extends B implements A {
public void pX() {
//System.out.println(x); //错误,原因不明确 x
//可以明确的指定 x
//访问接口的 x 就使用 A.x
//访问父类的 x 就使用 super.x
System.out.println(A.x + " " + super.x);
}
public static void main(String[] args) {
new C().pX();
}
}
7.内部类
一个类的内部又嵌套了另一个类结构,被嵌套的类称为内部类
内部类的分类:
1.定义在外部类局部位置上(比如方法内):
- 局部内部类(有类名)
- 匿名内部类(没有类名)!!!!!!!!!!!!
2.定义在外部类的成员位置上:
- 成员内部类(没用static修饰)
- 静态内部类(使用static修饰)
1.局部内部类
1.局部内部类是定义在外部局部类的局部位置,通常在方法
2.可以直接访问外部类的所有成员,包含私有的
3.不能添加访问修饰符(因为它的地位就是一个局部变量。局部变量是不能使用修饰符的)但是可以使用final 修饰
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u49IZytS-1665747352545)(E:\学习笔记\图片\Snipaste_2022-04-24_21-25-39.jpg)]
4.作用域:仅仅在定义它的方法或代码块中
5.局部内部类-----访问----->外部类的成员[访问方式:直接访问]
6.外部类----->访问------>局部内部类的成员[访问方式:创建对象再访问(注意:必须在作用域内)]
public class LocalInnerClass {
public static void main(String[] args) {
Outer02 outer02 = new Outer02();
outer02.m1();
}
}
class Outer02 {//外部类
private int n1 = 100;
private void m2() {
System.out.println("Outer02 m2()");
}//私有方法
public void m1() {//方法
//1.局部内部类是定义在外部局部类的局部位置,通常在方法
//3.不能添加访问修饰符(因为它的地位就是一个局部变量。局部变量是不能使用修饰符的)但是可以使用final 修饰
//4.作用域:仅仅在定义它的方法或代码块中
final class Inner02 {//局部内部类(本质仍然是一个类)
//2.可以直接访问外部类的所有成员,包含私有的
public void f1() {
//5.局部内部类可以直接访问外部类的成员
System.out.println("n1=" + n1);
m2();
}
}
//6.外部类在方法中,可以创建局部内部类---访问------>局部内部类的成员
Inner02 inner02 = new Inner02();
inner02.f1();
}
{//代码块
class Inner03{
}
}
}
7.外部其他类—>不能访问—>局部内部类(因为 局部内部类地位是一个局部变量)
8.如果外部类和局部内部类的成员重名时,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
public static void main(String[] args) {
Outer02 outer02 = new Outer02();
outer02.m1();
System.out.println("outer02的hashcode="+ outer02);
}
public void f1() {
//5.局部内部类可以直接访问外部类的成员比如下面的n1和m2()
System.out.println("n1=" + n1+"外部类n1= "+Outer02.this.n1);
System.out.println("Outer02.this 的 hashcode=" + Outer02.this);
m2();
}
2.匿名内部类
1.基于接口的匿名内部类
public class AnnonymousClass {
public static void main(String[] args) {
//基于接口的匿名内部类
//1.需求:实现一个IA接口,并创建对象
//2.传统的写法,写一个类实现该接口并创建对象
//3.如果Tiger/Dog类只使用一次,后面不再使用
//4.可以使用匿名内部类来简化开发
//5.tiger的编译类型? IA
//6.tiger的运行类型? 就是匿名内部类 XXX => Outer04$1
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 {
private int n1 = 10;
public void method(){
/*
底层
匿名内部类:
class Outer04$1 implements IA{
@Override
public void cry() {
System.out.println("老虎在哭....");
}
}
*/
//7.jdk底层在创建了匿名内部类Outer04$1,立即马上就创建了Outer04$1的实例,并且把地址
//返回给tiger
//8.匿名内部类Outer04$1使用一次,就不能使用tiger实例可以使用多次
IA tiger = new IA(){
@Override
public void cry() {
System.out.println("老虎在哭....");
}
};
tiger.cry();
System.out.println("tiger的运行类型=" + tiger.getClass().getName());
}
}
interface IA {//接口
public void cry();
}
//class Tiger implements IA{
// @Override
// public void cry() {
// System.out.println("老虎在哭....");
// }
//}
//class Dog implements IA{
// @Override
// public void cry() {
// System.out.println("小狗在哭....");
// }
//}
class Father {//类
public Father(String name){//构造器
}
public void test(){
}
}
结果:
老虎在哭....
tiger的运行类型=com.cheng.innerclass.Outer04$1
2.基于类的匿名内部类
//演示基于类的匿名内部类
//分析
//1.father编译类型: Father
//2.运行类型: Outer04$2
//3.底层会产生匿名内部类Outer04$2
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
}
*/
//4.同时也直接返回了匿名内部类Outer04$2的对象
Father father = new Father("jack"){
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
};
System.out.println("father对象的运行类型="+father.getClass().getName());
father.test();
{
/*
底层
匿名内部类:
class Outer04$1 implements IA{
@Override
public void cry() {
System.out.println("老虎在哭....");
}
}
*/
//7.jdk底层在创建了匿名内部类Outer04$1,立即马上就创建了Outer04$1的实例,并且把地址
//返回给tiger
//8.匿名内部类Outer04$1使用一次,就不能使用
IA tiger = new IA(){
@Override
public void cry() {
System.out.println("老虎在哭....");
}
};
tiger.cry();
System.out.println("tiger的运行类型=" + tiger.getClass().getName());
//演示基于类的匿名内部类
//分析
//1.father编译类型: Father
//2.运行类型: Outer04$2
//3.底层会产生匿名内部类Outer04$2
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
}
*/
//4.同时也直接返回了匿名内部类Outer04$2的对象
//5.注意("jack") 参数列表会传递给构造器
Father father = new Father("jack"){
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
};
System.out.println("father对象的运行类型="+father.getClass().getName());
father.test();
//基于抽象类的匿名内部类
Animal animal = new Animal(){
@Override
void eat() {
System.out.println("小狗吃骨头...");
}
};
animal.eat();
System.out.println("animal对象的运行类型="+animal.getClass().getName());
}
结果:
father对象的运行类型=com.cheng.innerclass.Outer04$2
匿名内部类重写了test方法
小狗吃骨头...
animal对象的运行类型=com.cheng.innerclass.Outer04$3
匿名内部类细节
匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有对象的特征
public class AnonymousInnerClassDetail01 {
public static void main(String[] args) {
Outer05 outer05 = new Outer05();
outer05.f1();
}
}
class Outer05{
private int n1 = 99;
public void f1(){
//1.创建一个基于类的匿名内部类
Person person = new Person(){
@Override
public void hi() {
//3.可以访问外部类的所有成员,包括私有成员
System.out.println("匿名内部类重写了hi方法"+n1);
}
};
person.hi();//运行时动态绑定,运行类型是Outer05&1
//2.也可以直接调用,匿名内部类本身也是返回一个对象
//4.不能添加访问修饰符,因为他的地位就是一个局部变量
//5.作用域:仅仅在定义他的方法或代码块中
//6.匿名内部类---->访问---->外部成员[访问方式:直接访问]
//7.如果外部类和匿名局部内部类的成员重名时,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
new Person(){
@Override
public void hi() {
System.out.println("匿名内部类重写了hi方法,哈哈哈");
}
@Override
public void ok(String str) {
super.ok(str);
}
}.ok("123");
}
}
class Person{//类
public void hi(){
System.out.println("Person hi()");
}
public void ok(String str){
System.out.println("Person ok()" + str);
}
}
//抽象类/接口...都可以写
匿名内部类的实践
- 将匿名内部类当做实参传递,简洁高效
public class InterfaceClassExercise01 {
public static void main(String[] args) {
//将匿名内部类当做实参传递,简洁高效(只使用一次更加方便)
f1(new IL() {
@Override
public void show() {
System.out.println("这是一幅名画");
}
});
//传统方式,(多次使用更加方便,形式比较统一)
f1(new Picture());
}
//静态方法,形参是接口类型
public static void f1(IL il){
il.show();
}
}
interface IL{
void show();
}
//类->实现IL =>编程领域称为(硬编码)
class Picture implements IL{
@Override
public void show() {
System.out.println("传统方法...");
}
}
小练习
public class InnerClassExercise02 {
public static void main(String[] args) {
CellPhone cellPhone = new CellPhone();
//1.传递的是实现了Bell接口的匿名内部类
//2.重写了 ring
//3.
cellPhone.alarmclock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了");
}
});
cellPhone.alarmclock(new Bell() {
@Override
public void ring() {
System.out.println("你这个年纪你怎么能睡得着的");
}
});
}
}
interface Bell{
void ring();
}
class CellPhone{
public void alarmclock(Bell bell){//形参是接口类型
bell.ring();//动态绑定机制和运行类型绑定
}
}
public class Homework04 {
public static void main(String[] args) {
Cellphone cellphone = new Cellphone();
cellphone.testwork(new Icalculate() {//会转到下方的double result = icalculate.work(n1,n2);//动态绑定
@Override
public double work(double n1, double n2) {
return n1 + n2;
}
},10,8);
}
}
interface Icalculate{
public double work(double n1,double n2);
}
class Cellphone{
public void testwork(Icalculate icalculate,double n1,double n2){
double result = icalculate.work(n1,n2);//动态绑定
System.out.println("输出计算结果:" + result);
}
}
3.成员内部类
public class MemberInnerClass01 {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.t1();
//外部其他类使用成员内部类的三种方式
//1.实际上是new Inner08();但是Inner08在outer08里面,相当于把 new Inner08()当做是Outer08的属性
//就是一个语法,不需要纠结
Outer08.Inner08 inner08 = outer08.new Inner08();
inner08.say();
//2.在外部类中编写一个方法 可以返回Inner08对象
Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
inner08Instance.say();
}
}
class Outer08{//外部类
private int n1 = 10;
public String name = "张三";
public void hi(){
System.out.println("hi");
}
//2.可以添加任意的访问修饰符
public class Inner08{//1.成员内部类,定义在外部类的成员位置上
private double sal = 99.8;
private int n1 = 66;
public void say(){
//可以直接访问外部类的所有成员,包含私有
//如果成员内部类的成员和外部类的成员重命,会遵守就近原则
//可以通过 外部类名.this.属性 来访问外部类成员
System.out.println("n1= "+ n1 +" name= "+name +"外部类的n1= "+Outer08.this.n1);
hi();
}
}
public Inner08 getInner08Instance(){
return new Inner08();
}
public void t1(){
//使用成员内部类
Inner08 inner08 = new Inner08();
inner08.say();
}
}
4.静态内部类
静态内部类是定义在外部类的成员位置,并且有static修饰
1.可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
2.可以添加任意访问修饰符,因为他的地位就是一个成员
3.作用域:同其他的成员,为整个类体
public class StaticInnerClass01 {//外部其他类
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.m1();
//外部其他类使用静态内部类
//方式一
//静态内部类是通过类名直接访问
Outer10.Inner10 inner10 = new Outer10.Inner10();
inner10.say();
//方式二
//编写一个方法,可以返回一个静态内部类的实例,
Outer10.Inner10 inner101 = outer10.getInner10();
System.out.println("========");
inner10.say();
//方式三,通过外部类名直接访问方法
Outer10.Inner10 inner10_ = Outer10.getInner10_();
System.out.println("********");
inner10_.say();
}
}
class Outer10{//外部类
private int n1 = 10;
private static String name = "张三";
private static void cry(){}
//Inner10就是静态内部类
//1.可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
//2.可以添加任意访问修饰符,因为他的地位就是一个成员
//3.作用域:同其他的成员,为整个类体
//4.内部类和外部类重命,通过外部类名.成员名
static class Inner10{
private static String name = "贾宝玉";
public void say(){
System.out.println(name+"外部name= "+Outer10.name);
cry();
}
}
public void m1(){//Outer10的一个方法
//4.外部类--->访问--->静态内部类 访问方式:创建对象,再访问
Inner10 inner10 = new Inner10();
inner10.say();
}
public Inner10 getInner10(){
return new Inner10();
}
//静态的
public static Inner10 getInner10_(){
return new Inner10();
}
}
8.枚举类
枚举类的值不能够再改变
1.自定义枚举类
public class Ennumeration02 {
public static void main(String[] args) {
System.out.println(Season.SPRING);
}
}
class Season{//类
private String name;
private String describe;//描述
public static final Season SPRING = new Season("春天", "温暖");
public static final Season SUMMER= new Season("夏天", "炎热");
public static final Season AUTUMN =new Season("秋天", "凉爽");
public static final Season WINTER = new Season("冬天", "寒冷");
//1.将构造其私有化,目的:防止直接new
//2.去掉set方法,防止修改属性
//3.在类的内部创建固定对象
//4.加final 在底层优化
private Season(String name, String describe) {
this.name = name;
this.describe = describe;
}
public String getName() {
return name;
}
public String getDescribe() {
return describe;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", describe='" + describe + '\'' +
'}';
}
}
2.关键字实现枚举
基本语法:
public class Ennumeration03 {
public static void main(String[] args) {
System.out.println(Season2.AUTUMN);
System.out.println(Season2.SUMMER);
}
}
enum Season2{//类
// public static final Season SPRING = new Season("春天", "温暖");
// public static final Season SUMMER= new Season("夏天", "炎热");
// public static final Season AUTUMN =new Season("秋天", "凉爽");
// public static final Season WINTER = new Season("冬天", "寒冷");
//使用enum来实现枚举类
//1.使用关键字enum来代替class
//2.public static final Season SPRING = new Season("春天", "温暖") 直接使用
//SPRING("春天", "温暖")
//3.若有多个常量(对象),使用逗号间隔即可
//4.先定义SPRING("春天", "温暖"),在定义属性private String name;
SPRING("春天", "温暖"),WINTER("冬天", "寒冷"),SUMMER("夏天", "炎热"),AUTUMN("秋天", "凉爽");
private String name;
private String describe;//描述
private Season2(String name, String describe) {//构造器
this.name = name;
this.describe = describe;
}
public String getName() {
return name;
}
public String getDescribe() {
return describe;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", describe='" + describe + '\'' +
'}';
}
}
3.枚举类注意事项
javap
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-USJBG2V8-1665747352546)(E:\学习笔记\图片\未命名文件 (3)].png)
1.使用enum关键字开发一个工具类时,默认会继承Enum类,而且是一个final类,使用javap来验证
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p6md2tN7-1665747352546)(E:\学习笔记\图片\Snipaste_2022-04-27_12-51-44.jpg)]
2.传统的 public static final Season SPRING = new Season(“春天”, “温暖”);简化成SPRING(“春天”, “温暖”),必须知道它调用的是哪一个构造器
3.如果使用无参构造器创建枚举对象,则实参列表和小括号都可以省略
SPRING("春天", "温暖"),WINTER("冬天", "寒冷"),SUMMER("夏天", "炎热"),AUTUMN("秋天", "凉爽"),SEASON_2;
private Season2(){//无参构造器
}
private Season2(String name, String describe) {//构造器
this.name = name;
this.describe = describe;
}
4.当有多个枚举对象时,使用,间隔。最后有一个分号
5.枚举对象必须放在枚举类的行首
4.Enum常用方法
public class EnumMethod {
public static void main(String[] args) {
//使用Season2 枚举类各种方法
Season2 autumn = Season2.AUTUMN;
//1.输出枚举对象的名称
System.out.println(autumn.name());
//2.autumn.ordinal()输出的是该枚举对象的次序/从0开始遍历
System.out.println(autumn.ordinal());
//3.从反编译可以看到有一个values 方法,返回Season2[]
//含有定义的所有枚举对象
Season2[] values = Season2.values();
for(Season2 season2:values){//增强for循环,迭代器
System.out.println(season2);
}
//4.valueOf将字符串转换成枚举对象,要求字符串中必须为已有的常量名,否则报异常
//1.根据你输入的"AUTUMN" 到Season2枚举对象去查找
//2.如果找到了,就返回,如果没有找到,就报错
Season2 autumn1 = Season2.valueOf("AUTUMN");
System.out.println("autumn1="+autumn1);
//autumn和autumn1是同一个对象
System.out.println(autumn == autumn1);
//5.compareTo:比较两个枚举常量,比较的是编号,结果是下标值相减
/* public final int compareTo(E o) {
Enum<?> other = (Enum<?>)o;
Enum<E> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal;
}*/
System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER));
}
}
5.Enum实现接口
public class EnnumerationDetail01 {
public static void main(String[] args) {
Music.CLASSICMUSIC.playing();
}
}
class A{
}
//enum实现的类不能继承但可以实现接口
enum Music implements IPlaying{
CLASSICMUSIC;
@Override
public void playing() {
System.out.println("播放音乐");
}
}
interface IPlaying{
public void playing();
}
9.注解
1.注解的理解
- Annotation也被称为元数据(Metadata),用于修饰解释 包、类、方法、属性、构造器、局部变量等数据信息
- 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息
- 在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替java EE旧版中所有遗留的繁冗代码和XML配置等
2.@overide
class Father{
public void fly(){
System.out.println("Father fly...");
}
public void say(){
}
}
class Son extends Father{
//1.@Override 注解放在fly上,表示fly方法重写了父类的fly方法
//2.如果没有写 @Override还是重写了父类 fly
//3.如果写了 @Override注解,编译器就会去检查该方法是否真的重写了父类方法
//如果的确重写了,责编已通过,如果没有构成重写,则编译出错
@Override
public void fly() {
System.out.println("Son fly");
}
@Override
public void say(){
}
}
@interface 不是interface,是注解类
@Target是修饰注解的注解,称为元注解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lRUeOAWV-1665747352547)(E:\学习笔记\图片\Snipaste_2022-04-28_17-31-48.jpg)]
3.@Deprecated
public class Deprecated_ {
public static void main(String[] args) {
A a = new A();
a.hi();
}
}
//1.@Deprecated 修饰某个元素,表示该元素已经过时
//2.即不再推荐使用,仍然可以使用
//3.查看 @Deprecated 注解类的源码
//4.可以修饰方法,类,字段,包,参数 等等
//5.@Deprecated可以做到新旧版本的兼容和过渡
@Deprecated
class A {
public int n1 = 10;
@Deprecated
public void hi(){
}
}
4.@SuppressWarning
all,抑制所有警告
boxing,抑制与封装/拆装作业相关的警告
cast,抑制与强制转型作业相关的警告
dep-ann,抑制与淘汰注释相关的警告
deprecation,抑制与淘汰的相关警告
fallthrough,抑制与switch陈述式中遗漏break相关的警告
finally,抑制与未传回finally区块相关的警告
hiding,抑制与隐藏变数的区域变数相关的警告
incomplete-switch,抑制与switch陈述式(enum case)中遗漏项目相关的警告
javadoc,抑制与javadoc相关的警告
nls,抑制与非nls字串文字相关的警告
null,抑制与空值分析相关的警告
rawtypes,抑制与使用raw类型相关的警告
resource,抑制与使用Closeable类型的资源相关的警告
restriction,抑制与使用不建议或禁止参照相关的警告
serial,抑制与可序列化的类别遗漏serialVersionUID栏位相关的警告
static-access,抑制与静态存取不正确相关的警告
static-method,抑制与可能宣告为static的方法相关的警告
super,抑制与置换方法相关但不含super呼叫的警告
synthetic-access,抑制与内部类别的存取未最佳化相关的警告
sync-override,抑制因为置换同步方法而遗漏同步化的警告
unchecked,抑制与未检查的作业相关的警告
unqualified-field-access,抑制与栏位存取不合格相关的警告
unused,抑制与未用的程式码及停用的程式码相关的警告
//1.当我们不希望看到这些警告的时候,可以使用SupressWarnings注解来抑制警告信息
//2.在{""}中,可以写入希望抑制(不显示)的警告信息
//3.关于SuppressWarnings 作用范围是和你放置的位置相关
//通常我们可以放置具体语句,方法,类
//@SuppressWarnings源码
//该注解类有数组 String[] value();设置一个数组,比如{"rawtypes","unchecked","unused"}
//@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
//@Retention(RetentionPolicy.SOURCE)
//public @interface SuppressWarnings {
// String[] value();
//}
@SuppressWarnings("all")
public static void main(String[] args) {
List list = new ArrayList();
list.add("jack");
list.add("tom");
list.add("mary");
int i;
System.out.println(list.get(1));
}
@SuppressWarnings({"rawtypes","unchecked","unused"})
public void f1(){
List list = new ArrayList();
list.add("jacky");
list.add("tom");
list.add("mary");
int i;
System.out.println(list.get(1));
}
}
5.JDK的元Annotation(元注解,了解)
- 元注解的基本介绍:
JDK的元Annotation用于修饰其他的Annotation
- 元注解的种类
- Retention //指定注解的作用范围,三种SOURCEC CLASS RUNTIME
- Target //指定注解可以用在哪些地方
- Documented //指定该注解是否会在javadoc中体现
- Inherited //子类会继承父类的注解
10.异常处理
1.基本介绍
- 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常。异常发生时,是任程序自生自灭,立刻退出终止。在Java中即,Java在编译或运行或者运行过程中出现的错误。
- 异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。
- Java中的异常可以是函数中的语句执行时引发的,也可以是程序员通过throw 语句手动抛出的,只要在Java程序中产生了异常,就会用一个对应类型的异常对象来封装异常,JRE就会试图寻找异常处理程序来处理异常。
- Throwable类是Java异常类型的顶层父类,一个对象只有是 Throwable 类的(直接或者间接)实例,他才是一个异常对象,才能被异常处理机制识别。JDK中内建了一些常用的异常类,我们也可以自定义异常。
- 执行过程中所发生的异常事件可分为两大类
- Error(错误):java虚拟机无法解决的严重问题。如JVM内部错误,资源耗尽等等
- Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件 Exception又分为两大类==:运行时异常[程序运行时发生的异常]和编译异常[编译时,编译器检查出异常]==
- 运行时异常:
- 编译异常:
2.入门语法
public class Exception01 {
public static void main(String[] args) {
int num1=10;
int num2=0;
//选中可能发生异常语句num1/num2 ctrl+alt+t快捷键
try {
int res = num1/num2;
} catch (Exception e) {
// e.printStackTrace();
System.out.println(e.getMessage());//输出异常内容
}
System.out.println("程序继续运行");
}
}
结果:
/ by zero
程序继续运行
3.异常体系图
常见的运行时异常:
1.NullPointerException:空指针异常
当应用程序试图在需要对象的地方使用 null时,抛出异常
public static void main(String[] args) {
String name = null;
System.out.println(name.length());
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3eYsAred-1665747352547)(E:\学习笔记\图片\Snipaste_2022-04-29_15-59-33.jpg)]
2.ArithmeticException数学运算异常
当程序出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例
3.ArrayIndexOutOfBoundsException数组越界异常
4.ClassCastException类型转换异常
父类可以指向子类的对象即
A b = new B();//向上转型
B b1 = (B)b;//向下转型(强制类型转换)
class A{}
class B extends A{}
class C extends A{}
子类不可以指向父类的对象即 下方是错误的
B a = new A();
编译不会出错,但是运行时会出现ClassCastException类型转换异常
C c2 = (C)b;
5.NumberFormatException数字格式不正确异常
将字符串转换为数字,但该字符串不能转换抛出此异常
public class Exception02 {
public static void main(String[] args) {
String name = "程冠希";
//将string转换为int
int num = Integer.parseInt(name);
System.out.println(num);
}
}
常见的编译期异常:
编译异常是指在编译期间就必须处理的异常,否则代码不能通过编译
1.ClassNotFoundException(类找不到异常)
2.FileNotFoundException(编译文件夹中找不到,就是发布到tomcat中的,不是工程中)
3.SQLException :提供有关数据库访问错误或其他错误的信息的异常。( 比如SQL语句写错,访问的表不存在,连接数据库失败等等)
4.IOexception:IO流异常。一般在读写数据的时候会出现这种问题。
5.EOFException:当输入过程中意外到达文件或流的末尾时,抛出此异常。
4.异常处理机制
1.try/catch
public static void main(String[] args) {
try {
可能有异常的代码
}catch (Exception e){
捕获到异常
1.当异常发生时,系统将异常封装成Exception 对象e,传递给catch
2.得到异常后可自行处理,例如打印异常
3.如果没有发生异常,catch代码块不执行
}finally {
1.不管try代码块是否有异常都要执行finally
2.通常将释放资源的代码放在finally
}
}
2.throws
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L83jYTQa-1665747352548)(E:\学习笔记\图片\未命名文件.png)]
方法二出现异常可以throw到调用它的方法让方法一处理,如果都不处理就返回到JVM这时JVM继续摆烂,直接输出异,中断程序
- 如果没有显示使用哪一种处理机制默认是throws
一.try-catch异常处理细节
public static void main(String[] args) {
//1.如果异常发生了,则异常发生后面的代码不会执行,直接进入到catch块
//2.如果异常没有发生,则顺序执行try的代码块,不会进入到catch
//3.如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)则使用如下代码-finally
try {
String name = "程冠希";
//将string转换为int
int num = Integer.parseInt(name);
System.out.println(num);
} catch (NumberFormatException e) {
System.out.println("异常信息:"+e.getMessage());
} finally {
System.out.println("finally代码块被执行");
}
}
4.如果try代码块有可能有多个异常可以使用多个catch分别捕获不同的异常,相应处理
要求子类异常写在前面,父类异常写在后面
public class Exception02 {
public static void main(String[] args) {
//1.如果try代码块有可能有多个异常
//可以使用多个catch分别捕获不同的异常,相应处理
//要求子类异常写在前面,父类异常写在后面
try {
Person person = new Person();
person = null;
System.out.println(person.getName());
int n1 = 10;
int n2 = 0;
int res = n1/n2;
} catch (NullPointerException e) {
System.out.println(e.getMessage());
}catch (ArithmeticException e){
System.out.println(e.getMessage());
}
finally {
System.out.println("执行finally代码块");
}
}
}
class Person{
String name;
public String getName() {
return name;
}
}
//没有抛出ArithmeticException异常,因为程序到 System.out.println(person.getName());就终止了
null
执行finally代码块
5.只有try-finally相当于没有捕获异常
这样执行完finally代码块的内容就会结束,目的是为了释放资源
public static void main(String[] args) {
try {
int n1 = 10;
int n2 = 0;
System.out.println(n1/n2);
} finally {
System.out.println("执行了finally");
}
System.out.println("程序继续执行");//此语句不再执行
}
执行了finally
二、throws异常处理细节
1.入门语法
public class Exception02 {
public static void main(String[] args) {
}
//抛出异常
public void f2() throws FileNotFoundException {
//创建了一个文件流对象
FileInputStream fileInputStream = new FileInputStream("d://aa.txt");
}
}
2.细节
- 对于编译异常,程序中必须处理,比如
try-catch
或者throws
- 对于运行时异常,程序中如果没有处理,默认就是
throws
的方式处理 - 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型
- 在
throws
过程中,如果有方法try-catch
,就相当于处理异常,就可以不必throws
throws的细节实现跳过了,接下来就是java的常用类介绍了
一些碎碎念:
都在说互联网越来越卷了,动起来吧,总比摆烂强,一定要找准自己的方向,不一定要是java,java人确实多,考研也好就业也罢,总得先有个保底的,不然应届生身份没有了就很难受。
希望看到这篇文章的你能动起来加油吧!!