Java基础总结三(泛型、异常)

Java 泛型是什么?一文带你吃透泛型 它是一个泛型类,而我之前使用的时候并没有传递,说明 Java 语法是允许的,这个时候传递的类型是 Object 类,虽然它是所有类的父类,可以存储任意的类型,但是在遍历、获取元素时需要原来的类型就要进行强制转换。泛型接口有两使用方式,要么在实现接口时确定泛型类的类型,要么在实现接口时先不确定泛型类类型,而在实例化对象时再确定。这个时候就会出现一些问题,假如往链表里存储了许多不同类型的数据,在强转的时候就要判断每一个原来的类型,这样就很容易出现错误。,泛型在类中可以创建变量,也可以作为方法的参数或者返回值。 阅读详情

Java基础总结三(泛型、异常)

泛型

泛型的创建

泛型类

我们最常用泛型的地方就是集合,因此,我们编写自己的List来体会泛型:

public class TestList<T> {

    private Object[] instances = new Object[0];

    public T get(int index) {
        return (T) instances[index];
    }

    public void set(int index,T newInstance) {
        instances[index] = newInstance;
    }

    public void add(T newInstance) {
        instances = Arrays.copyOf(instances,instances.length + 1);
        instances[instances.length - 1] = newInstance;
    }
}

看一下使用方法:

TestList<String> testList = new TestList<>();
testList.add("wlk");
String str = testList.get(0);
System.out.println(str); // wlk
泛型接口

我们除了创建泛型类,泛型接口与其很类似:

public interface Shop <T>{
    T buy();
    float refund(T item);
}

// 实现
public class RealShop<E> implements Shop<E>{
    @Override
    public E buy() {
        return null;
    }

    @Override
    public float refund(E item) {
        return 0;
    }
}

再比如,我们想要实现一个水果商店:

public class Fruit {
}

public class Apple extends Fruit{
}

public class FruitShop<E> implements Shop<E>{
    @Override
    public E buy() {
        return null;
    }

    @Override
    public float refund(E item) {
        return 0;
    }
}

FruitShop<Apple> fruitShop = new FruitShop<>(); // 这个商店卖苹果
FruitShop<Phone> stringShop = new FruitShop<>(); // 这个水果商店卖手机??? 当然不和逻辑

由于我们的商店泛型 E 没有加以限制,会导致错误,我们来给他加上限制:

public class FruitShop<E extends Fruit> implements Shop<E>{
    @Override
    public E buy() {
        return null;
    }

    @Override
    public float refund(E item) {
        return 0;
    }
}

现在这个水果商店只可以卖 Fruit 或者 Fruit 的子类,如Apple,而不能卖手机。

泛型方法

自己声明了泛型的方法

泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型 。

我们给我们的苹果商店创建一个方法,它支持用其他水果换取苹果:

public class FruitShop<E extends Fruit> implements Shop<E>{
    @Override
    public E buy() {
        return null;
    }

    @Override
    public float refund(E item) {
        return 0;
    }

    public <T extends Fruit> E exchange(T item){
        return null;
    }
}

// 使用
FruitShop<Apple> appleShop = new FruitShop<>();
Apple apple = appleShop.<Banana>exchange(new Banana());
//类型推导,<Banana>可省略
Apple apple = appleShop.exchange(new Banana());

类型擦除

泛型的好处是在编译期进行类型检查和类型转换,且泛型只在编译期有效。泛型是在 JDK 1.5 里引入的,如果不做泛型擦除,那么 JVM 需要对应使得能正确的的读取和校验泛型信息;另外为了兼容老程序,需为原本不支持泛型的 API 平行添加一套泛型 API。

在运行期,声明时的泛型参数会被擦除,在使用处的泛型会被泛型的父类替换,如<E extends Fruit>,此时使用E的地方会被Fruit替换。

泛型的协变与逆变

定义:如果A、B表示类型,f()表示一个类型的构造函数,Type1≤Type2表示Type1是Type2的子类型,Type1≥Type2表示Type1是Type2的超类型;

  • f()是协变(covariant)的,当A≤B时有f(A)≤f(B)成立;
  • f()是逆变(contravariant)的:当A≤B时有f(B)≤f(A)成立;
  • f()是不变(invariant)的,当A≤B时上述两个式子均不成立,即f(A)与f(B)相互之间没有继承关系。

对于任意两个不同的类型 Type1 和 Type2,不论它们之间具有什么关系,给定泛型类 G<T>,G<Type1> 和 G<Type2> 都是没有关系的,即 Java 中泛型是不变的,而数组是协变的,可以验证以下:

ArrayList<Number> list = new ArrayList<Integer>(); // 编译器报错

// 可以顺利通过编译,正常使用。
Number[] arr = new Integer[5];
arr[0] = 1;
// 但也有一定的问题,这个数组接受Number其他子类也不会在编译期报错,而在运行期报错。泛型从根源杜绝了这种错误

在Java的泛型中,是可以支持协变与逆变的,但会有很大的限制:

  • ? extends T(上边界通配符)实现协变关系,表示?是继承自T的任意子类型。也表示一种约束关系,只能提供数据,不能接收数据。
  • ? super T(下边界通配符)实现逆变关系,表示?是T的任意父类型。也表示一种约束关系,只能接收数据,不能提供数据。

协变所谓只能提供数据,不能接收数据,是指在实例化出泛型类后,仅可以调用该类中返回值为泛型的方法,而不可以调用参数为该泛型的方法。

逆变则恰好相反。

那么如此限制,?在我们实际开发中应该如何应用呢?

List<? extends Number> list = new ArrayList<Integer>();

这样的用法在我们平时是用不到的,只有一些场景化的需要,才会使用到泛型通配符。就拿我们的水果商店举例,我们现在有这样一个需求,需要计算集合中水果的总重量,所以编写了如下方法:

public int totalWeight(List<? extends Fruit> list) {
    int total = 0;
    for(Fruit fruit : list) {
        total += fruit.weight;
    }
    return total;
}

// 使用起来,就可以向这个方法中传入任意Fruit子类的集合了
List<Apple> appleList = new ArrayList<>();
totalWeight(appleList);
List<Banana> bananaList = new ArrayList<>();
totalWeight(bananaList);

再举一个逆变的用法:

List<Apple> appleList = new ArrayList<Fruit>();

当然这种用法是极其少有的,不做讨论。我们给苹果类添加一个方法,这个方法的作用就是给苹果装入集合:

public class Apple extends Fruit{

    public void addToList(List<? super Apple> list) {
        list.add(this);
    }

}

这样,当我们传来Apple集合的时候,就会把Apple装入这个集合,同时,我们也可以传入Fruit的集合:

List<Apple> appleList = new ArrayList<>();
List<Fruit> fruitList = new ArrayList<>();
List<Banana> bananaList = new ArrayList<>();

Apple apple = new Apple();
apple.addToList(appleList); // 编译通过
apple.addToList(fruitList); // 编译通过
apple.addToList(bananaList); // 报错

异常

异常体系

Java中异常的体系是树形结构,所有异常的超类是Throwale,它有俩个子类:Error和Exception,分别表示错误和异常,其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常,这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。

  1. Error与Exception
    • Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
    • Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常,程序中应当尽可能去处理这些异常。
  2. 运行时异常和非运行时异常
    • 运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,程序中可以选择捕获处理,也可以不处理。
    • 非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类,从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过,如IOException、SQLException等以及用户自定义的Exception异常。

异常处理

  • 在try中return后,依旧会执行finally。
  • finally语句在return语句执行之后return返回之前执行的。
  • finally块中的return语句会覆盖try块中的return返回。
  • 如果finally语句中没有return语句覆盖返回值,那么原来的返回值可能因为finally里的修改而改变也可能不变(具体区分值和引用)。
  • 当发生异常后,catch中的return执行情况与未发生异常时try中return的执行情况完全一样。
  • 在Java中如果不发生异常的话,try/catch不会造成任何性能损失。在 Java 类编译后,正常流程与异常处理部分是分开的,类会跟随一张异常表,每一个try-catch都会在这个表里添加行记录。当执行抛出了异常时,首先去异常表中查找是否可以被catch,如果可以则跳到异常处理的起始位置开始处理,如果没有则原地return,并且copy异常的引用给父调用方,接着看父调用的异常表,以此类推。

我们来看一个例子:

public int test(){
    int i = 1;
    try {
        i++;
        return i;
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        System.out.println("finally");
        i++;
    }
    return 0;
}

System.out.println(test()); 

// out ->
finally
2

我们看到,finally执行了,那么i++应该也是执行了,为什么返回2,我们通过查看字节码可知

Code:
      stack=2, locals=4, args_size=1
         0: iconst_1
         1: istore_1
         2: iinc          1, 1
         5: iload_1
         6: istore_2
         7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        10: ldc           #12                 // String finally
        12: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        15: iinc          1, 1
        18: iload_2
        19: ireturn
        20: astore_2
        21: aload_2
        22: invokevirtual #15                 // Method java/lang/Exception.printStackTrace:()V
        25: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        28: ldc           #12                 // String finally
        30: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        33: iinc          1, 1
        36: goto          53
        39: astore_3
        40: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        43: ldc           #12                 // String finally
        45: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        48: iinc          1, 1
        51: aload_3
        52: athrow
        53: iconst_0
        54: ireturn

总结一下,总体的意思就是,当执行完try块的时候,会计算return表达式的值,然后把这个返回值存在另一个临时变量里面,最后返回的时候会重新读取存放的变量,因此在finally后面无论如何修改,都不会影响返回值。那么,如果finally中加了return后,结果就会覆盖原有的返回值了。

ADS使用Smith圆图进行阻抗匹配 在处理RF系统的实际应用问题时,总会遇到一些非常困难的工作,对各部分级联电路的不同阻抗进行匹配就是其中之一。一般情况下,需要进行匹配的电路包括天线与低噪声放大器(LNA)之间的匹配、功率放大器输出(RFOUT)与天线之间的匹配、LNA/VCO输出与混频器输入之间的匹配。匹配的目的是为了保证信号或能量有效地从“信号源”传送到“负载”。 阻抗匹配(impedance matching) 信号源内阻与所接传输线的特性阻抗大小相等且相位相同,或传输线的特性阻抗与所接负载阻抗的大小相等且相位相同,分别称为传输线的输 阅读详情

相关推荐

华为HCIP-001:PPPOE配置模拟实验

华为HCIP01:PPPOE配置模拟实验 实验环境 pppoe-client上面的接口信息 [AR1]dis ip interface brief *down: administratively down ^down: standby (l): loopback (s): spoofing The number of interface that is UP in Physical is 2 The number of interface that is DOWN in Physical is 1 Th

兔子乖乖 1802

java异常处理机制

文章目录java异常处理机制一、异常描述二、异常处理机制01、使用try...catch捕获异常02、异常类的继承体系03、Java7提供的多异常捕获04、访问异常信息05、使用finally回收资源06、异常处理的嵌套07、自动关闭资源的try语句三、Checked(检查)异常和Runtime(非受查)异常体系01、两者关系与区别02、使用throws声明抛出异常四、使用throw抛出异常01、...

qq_36649701的博客 874

Java异常类和常用类,容器,泛型

异常类分两大类型:Error类代表了编译和系统的错误,不允许捕获;Exception类代表了标准Java库方法所激发的异常。Exception类还包含运行异常类Runtime_Exception和非运行异常类Non_RuntimeException这两个直接的子类。运行异常类对应于编译错误,它是指Java程序在运行时产生的由解释器引发的各种异常。运行异常可能出现在任何地方,且出现频率很高,因此为了避免巨大的系统资源开销,编译器不对异常进行检查。所以Java语言中的运行异常不一定被捕获。

2301_77204575的博客 751

STM32F103C8T6通过ESP8266连接阿里云物联网平台(附代码)

STM32F103C8T6连接阿里云物联网平台(1)—阿里云lot Studio控制 Web开发 分享一下自己使用stm32f103c8t6通过ESP_01模块连接阿里云物联网平台,实现温湿度上传和控制命令下达的过程,能力有限,用的是最简单的方法,如有错误,多多担待。 一、硬件选型 1、 stm32f103c8t6 2、ESP_01 wifi模块 3、其他 二、硬件连接 WSP_01 STM32F103C8T6 RXD PA2 TXD PA3 RES PA4 VCC 3.3

weixin_A13253323604 3万+

摩擦纳米发电机测试系统全解析:从硬件配置到软件控制

本文全面解析摩擦纳米发电机(TENG)测试系统,涵盖硬件配置、软件控制及系统集成。详细介绍NI USB-6003等采集卡的选择与使用,以及一体化控制软件的功能与优势,帮助研究人员高效评估纳米材料发电性能。系统支持自动测试与数据分析,显著提升测试效率与准确性。

weixin_28720767的博客 463

异常、泛型、集合框架

Java无法为这个世界上全部的问题都提供异常类来代表,如果企业自己的某种问题想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类。1、自定义编译时异常:定义一个异常类继承Exception类,并重写构造方法,通过throw new 异常类(xxx) 创建异常对象并抛出。2、自定义运行时异常:定义一个异常类继承RuntimeException类,并重写构造方法,通过throw new 异常类(xxx) 创建异常对象并抛出。//自定义编译时异常//1、继承Exception做爸爸。

2303_76664877的博客 1043

RoboDK 自定义机器人

本文介绍了如何在RoboDK中自定义机器人模型的方法。主要内容包括:1)通过CAD软件处理3D模型后导入RoboDK,使用分割工具简化模型结构;2)配置机器人的DH参数和关节运动范围;3)验证机器人运动效果后导出.robot文件。该方法可使自制机器人获得与ABB等商用机器人相同的仿真和控制功能。文章详细说明了模型处理、参数设置和验证的完整流程,为机器人开发者提供了实用的技术指导。

zhbi98 的技术 Blogs 2665

泛型与异常处理

1.1    异常的继承体系 在Java中使用Exception类来描述异常。 查看API中Exception的描述,Exception 类及其子类是 Throwable 的一种形式,它用来表示java程序中可能会产生的异常,并要求对产生的异常进行合理的异常处理。   继续观察,我们可以发现Exception有继承关系,它的父类是Throwable。Throwable是Java 语言中所有

小菜鸟的博客 693

基于STM32设计的老人摔倒检测报警系统【升级版】(235)

在 `235 基于STM32设计的老人摔倒检测报警系统(OneNet+MQTT)` 项目基础上增加了心率、血氧、体温测量3个功能。

1511

C#函数返回多个值实现实例

本文实例讲解C#函数返回多个值多种实现方法。

qq_30725967的博客 1170

11.泛型与异常

泛型与异常,包括throws和throw区别,throws和try catch 区别,内含练习代码

改变从现在开始 405

【高级】系统架构师 | 2026年上半年案例分析真题

标准答案:系统因缺乏足够历史数据(用户行为、物品信息或评分等),难以做出准确推荐的问题。另外两种:物品冷启动(新课程 / 新知识点缺少互动数据)系统冷启动(平台上线初期整体数据稀缺)类型典型表现常见缓解用户冷启动新注册学员无历史问卷/前测、热门兜底、人口统计学特征、知识图谱前置测评物品冷启动新课无人学无人评内容特征推荐、专家标注、探索流量系统冷启动新平台双边都稀缺规则引擎、运营冷启、知识图谱强约束路径本题已点明「用户冷启动」,另外两种按推荐系统经典三分法作答即可。

大胆尝试,小心实践 360

Java基础总结三(泛型、异常

当然在这还有更多整理总结的Java进阶学习笔记和面试题未展示,其中囊括了。

2401_83641098的博客 904

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【Java编程动手学】Java三大核心特性:异常、注解与泛型

Java异常处理、注解系统和泛型机制是构建健壮程序的三大支柱。异常体系采用分层结构(Throwable/Error/Exception),通过声明式、捕获式和异常链实现错误处理。注解系统支持元数据编程,从编译期检查(@Override)到运行时处理(自定义注解)。泛型通过类型参数约束和通配符(PECS原则)确保类型安全,同时保持代码灵活性。这些特性共同保障了Java程序的安全性与可扩展性。

杰西笔记 976

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

JAVA基础学习(三)——反射、注解、泛型、集合、IO及异常等

本文汇总一下杂七杂八的知识,重要程度会在文中表述。一、反射在学golang时候接触过反射,但并没有看懂,这里温习一下。现在给你一个类Object,要获取他的字段,方法,父类等信息,如何做呢?知道这个类是啥,求上述信息很简单,但万一不知道呢?在测试中可能就会出现这种情况。反射就是程序在运行期间,获取对象的各种信息的过程。换句话说,根据class实例,获取class各种信息的过程就是反射。任何一个类class的实例都是由JVM动态加载实现的。

m0_45978228的博客 1845

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Java语言基础(三)——异常、容器、泛型

一、异常 实际开发工作中,遇到的情况不可能是完全理想的,其遇到的问题就叫异常。Exception。 1.1、简单异常 1.1.1、检查型异常 最具代表性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如用户要打开一个不存在的文件时引发的异常,这些异常在编译时不能被简单地忽略。 1.1.2、运行时异常 是可能被程序员避免的异常,与检查性异常相反,运行时异常可以在编译时忽略 1.1.3、错误Error 错误不是异常,而是脱离程序员控制的问题。错误在代码经常被忽略。例如当栈溢出,一个异常就

weixin_42956490的博客 639

Java语法基础三:异常处理、泛型和反射

异常处理的分类、异常处理机制;泛型的定义、作用和使用,和反射的定义、操作示例和优缺点

Xyuan的博客 1048

【Java编程】JavaSE基础总结(三):异常机制、泛型

在理想的情况下,我们的程序会按照我们的思路去运行,按理说是不会出现问题的,但是,代码实际编写后并不一定是完美的,可能会有我们没有考虑到的情况,如果这些情况能够正常得到一个错误的结果还好,但是如果直接导致程序运行出现问题了呢?

Data · Model · Agent · Repeat 588

Effective Java读书笔记(三):泛型、枚举、注解、异常

来到读书笔记的第三篇了,这一次的主题是讲泛型、枚举、注解这三个Java1.5引入的语言特性。关于泛型,很久以前我写过一篇初识的文章,http://blog.youkuaiyun.com/leelit/article/details/39504873,里面的一些基础知识现在看起来依然能起到复习作用。而另外两个特性的基础知识这里不再展开,因为Effective Java这本书讲的就是一些编程技巧或者说良好的习惯。然

leelit笔记本 1168

1.Java基础(三)-异常、泛型、匿名内部类、集合

项目 数据库管理系统StudentSystemV1.0 包名结构: cn.system.student.ocean888.entity --实体类 Student.java cn.system.student.ocean888.manager --管理类 StudentManager.java cn.system.student.ocean888.test --测试类 SystemTest.java cn.system.studen

Love&Share 3238

异常,泛型,集合框架

java无法为这个世界上全部的问题都提供异常类来代表,如果企业自己的某种问题,想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了.

liang_zhi_bin的博客 435

【java基础】泛型

1、 泛型概述 我们都知道集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成Object类型。当我们在取出每一个对象,并且进行相应的操作,这时必须采用类型转换。 大家观察下面代码: public class GenericDemo { public static void main(String[] args) { Collection coll = new Arr...

宜春 1万+
上一篇: Java基础总结二(集合)
下一篇: Java集合源码分析—ArrayList
<天各一方>
博客等级 码龄6年 17粉丝 17原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值