java面试题-泛型异常反射

news2024/9/25 19:20:59

泛型

1.什么是泛型?

Java是一种强类型语言,数据类型在编译时必须确定。如果我们想要在代码中使用不同类型的数据,那么就需要为每种类型分别写出相应的代码。这样会导致代码冗长、重复,也不便于维护。为了解决这个问题,Java引入了泛型机制,允许在类、接口、方法中使用类型参数,使代码更加通用、简洁、安全。

示例代码:

// 不使用泛型
List list = new ArrayList();
list.add("hello");
String str = (String) list.get(0); // 需要强制类型转换,容易出现类型转换异常

// 使用泛型
List<String> list = new ArrayList<String>();
list.add("hello");
String str = list.get(0); // 不需要强制类型转换,类型安全

2.泛型类如何定义使用?

泛型类定义的语法格式如下:

public class 类名<类型参数列表> {
    // 成员变量、方法等
}

其中,类型参数列表是用尖括号包围起来的一组类型参数,可以有多个,用逗号隔开。类型参数可以在类中的任何位置使用。泛型类的实例化时需要指定类型实参。

示例代码:

public class ClassName<T> {
    private T value;

    public ClassName(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

ClassName<Integer> obj = new ClassName<Integer>(123);
int value = obj.getValue();

3.泛型接口如何定义使用?

泛型接口定义的语法格式如下:

public interface 接口名<类型参数列表> {
    // 方法声明
}

其中,类型参数列表和泛型类的类型参数列表语法相同,可以在接口中的任何位置使用。泛型接口的实现类需要指定类型实参。

public interface InterfaceName<T> {
    void doSomething(T parameter);
}

InterfaceName<String> obj = new InterfaceName<String>() {
    public void doSomething(String parameter) {
        System.out.println(parameter);
    }
};
obj.doSomething("hello");

4.泛型方法如何定义使用?

泛型方法定义的语法格式如下:

修饰符 <类型参数列表> 返回值类型 方法名(形参列表) {
    // 方法体
}

其中,类型参数列表和泛型类、泛型接口的类型参数列表语法相同,可以在方法中的任何位置使用。在方法调用时,可以显式指定类型实参,也可以通过参数类型推断省略类型实参。

public class ClassName {
    public <T> void methodName(T parameter) {
        System.out.println(parameter);
    }
}

ClassName obj = new ClassName();
obj.<String>methodName("hello");

5.泛型的上限和下限?

泛型的上限和下限是限制类型参数的边界。泛型的上限使用 extends 关键字,表示类型参数必须是指定的类型或其子类。泛型的下限使用 super 关键字,表示类型参数必须是指定的类型或其超类。

// 上限
public class ClassName {
    public <T extends Number> void methodName(T parameter) {
        System.out.println(parameter);
    }
}

ClassName obj = new ClassName();
obj.methodName(123); // OK
obj.methodName("hello"); // 编译错误,String不是Number的子类

// 下限
public void methodName(List<? super Integer> parameter) {
    parameter.add(123);
    parameter.add(3.14); // 编译错误,3.14是double类型
}

List<Number> list1 = new ArrayList<Number>();
methodName(list1); // OK
List<Object> list2 = new ArrayList<Object>();
methodName(list2); // 编译错误,Object不是Integer或Integer的超类

6.如何理解Java中的泛型是伪泛型?

Java中的泛型是通过类型擦除实现的,即在编译时擦除类型信息,在运行时不保留类型信息。因此,在运行时无法获得泛型类型参数的具体类型。这样,Java中的泛型就成了一种“伪泛型”。泛型类型信息在编译时可以检查,但在运行时被擦除,这是泛型机制的一个局限性,但也是Java泛型的一个优点,因为这种方式避免了运行时的类型转换错误,并提高了运行时的性能。

另外,Java中的泛型还存在一个“类型擦除”问题。在使用泛型时,类型参数实际上被转换成了其边界类型或 Object 类型。这就导致了一些限制,比如无法创建泛型数组,无法在泛型类型中使用基本类型等。虽然Java中的泛型有一些限制,但仍然是一种非常有用的机制,可以使代码更加通用、简洁、安全。

public class ClassName<T> {
    private T value;

    public ClassName(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

ClassName<Integer> obj1 = new ClassName<Integer>(123);
ClassName<String> obj2 = new ClassName<String>("hello");

System.out.println(obj1.getClass().getName()); // ClassName
System.out.println(obj2.getClass().getName()); // ClassName

// 泛型类型信息在运行时被擦除

异常

1.Java异常类层次结构?

Java异常类层次结构是异常处理的基础,如下所示:

java.lang.Object
        |
        +--java.lang.Throwable
                |
                +--java.lang.Error
                |
                +--java.lang.Exception
                        |
                        +--java.io.IOException
                        |
                        +--java.sql.SQLException
                        |
                        +--其他异常类

所有的异常类都继承自 Throwable 类。Throwable 类有两个直接子类:Error 和 Exception。Error 表示系统级别的错误和资源耗尽等无法恢复的错误,程序通常无法处理。例如,OutOfMemoryError 表示内存不足错误。Exception 是程序中可能会遇到的异常情况,程序可以通过捕获和处理这些异常来恢复正常运行。Exception 又分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。可查的异常是指在编译时必须进行处理的异常,这些异常必须被捕获或声明抛出。不可查的异常是指在编译时无法确定是否需要处理的异常,这些异常不需要被捕获或声明抛出。

2.可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)区别?

可查的异常必须在编译时进行处理,否则编译器会报错。这些异常通常是由系统或程序逻辑错误引起的,例如文件不存在、输入输出错误等。常见的可查异常包括 IOException、SQLException 等。

不可查的异常通常是由程序设计错误引起的,例如空指针异常、类型转换异常等。这些异常通常发生在运行时,编译器无法检测到。不可查的异常不需要在方法签名中声明抛出,并且不需要在调用时进行处理。

3.throw和throws的区别?

throw 和 throws 关键字都用于处理异常,但含义不同。throw 关键字用于抛出一个异常对象。在方法中,当程序发现异常情况时,可以使用 throw 关键字抛出一个异常对象。例如:

if (x == null) {
    throw new NullPointerException("x is null");
}

throws 关键字用于在方法签名中声明可能抛出的异常。在方法中,如果可能会抛出一个异常,但是不想在方法内部进行处理,可以在方法签名中使用 throws 关键字声明可能抛出的异常。例如:

public void foo() throws Exception {
    // 方法体
}

4.Java 7 的 try-with-resources?

Java 7 引入了 try-with-resources 语句,这是一种简化关闭资源代码的方法。在 try-with-resources 语句中,可以自动关闭实现了 java.lang.AutoCloseable 接口的资源,例如文件或数据库连接等。

以下是一个使用 try-with-resources 语句的简单示例:

public class Demo {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
            String line = reader.readLine();
            while (line != null) {
                System.out.println(line);
                line = reader.readLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的示例中,BufferedReaderFileReader 都实现了 AutoCloseable 接口。在 try-with-resources 语句中,我们创建一个 BufferedReader 对象和一个 FileReader 对象,并将它们作为资源传递给 try 语句。当程序离开 try 块时,JVM 会自动关闭这两个资源。

try-with-resources 语句可以有多个资源,例如:

try (Resource1 res1 = new Resource1(); Resource2 res2 = new Resource2()) {
    // ...
}

在这种情况下,两个资源都会被自动关闭。如果资源之间有依赖关系,可以按照需要在 try-with-resources 语句中创建和关闭资源。

5.Java 异常的底层实现,以及Exception Table是什么?

Java 异常的底层实现涉及到 Java 虚拟机(JVM)中的 Exception Table。在 Java 代码编译成字节码时,编译器会将所有可能抛出异常的代码块标记为异常处理器。这些异常处理器被编译器放在 Exception Table 中,并包含了异常处理器的入口地址、代码块的起始和结束位置、以及异常类型等信息。

当程序执行到可能抛出异常的代码块时,JVM 会检查 Exception Table 中是否存在与当前抛出的异常匹配的异常处理器。如果存在,则将程序控制流转移到对应的异常处理器,执行异常处理器中的代码。如果不存在匹配的异常处理器,则将异常抛出到调用栈上层的异常处理器或者 JVM 运行时系统中进行处理。

下面是一个简单的示例,用于演示 Exception Table 的实现:

public class Demo {
    public static void main(String[] args) {
        int result = divide(10, 0);
        System.out.println("Result: " + result);
    }

    public static int divide(int a, int b) {
        int result = 0;
        try {
            result = a / b;
        } catch (ArithmeticException e) {
            System.out.println("Exception caught: " + e.getMessage());
        }
        return result;
    }
}

在上面的示例中,divide() 方法计算两个整数的商。如果除数为 0,则会抛出一个 ArithmeticException 异常。在 main() 方法中,调用 divide() 方法计算结果,并打印计算结果。

当执行到 result = a / b 语句时,JVM 会检查 Exception Table 中是否存在匹配 ArithmeticException 异常的异常处理器。在这个示例中,存在一个匹配的异常处理器,它位于 catch (ArithmeticException e) 代码块中。JVM 将程序控制流转移到异常处理器中,并执行其中的代码,打印异常信息。然后,JVM 将程序控制流返回到调用 divide() 方法的地方,继续执行程序。


反射

  1. 什么是反射?

反射是一种在运行时动态地获取类的信息和调用类的方法的能力。Java 反射 API 可以让程序在运行时动态地创建对象、访问对象属性、调用对象方法以及获取对象信息等,从而增强了程序的灵活性和可扩展性。

2.反射的使用?

反射可以用来实现一些高级的特性,比如依赖注入、框架配置和代理等。反射 API 主要提供了以下几个类来实现反射功能:

  • Class 类:表示一个类的类型,可以用来获取类的信息、实例化对象、访问类的静态成员和调用类的方法等。

  • Field 类:表示一个类的字段,可以用来访问和修改对象的属性。

  • Method 类:表示一个类的方法,可以用来调用对象的方法。

  • Constructor 类:表示一个类的构造函数,可以用来实例化对象。

下面是一个简单的示例,用于演示反射的使用:

public class Demo {
    private String message;

    public Demo(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("Demo");
        Constructor<?> constructor = cls.getConstructor(String.class);
        Object obj = constructor.newInstance("Hello, world!");
        Method method = cls.getMethod("getMessage");
        String message = (String) method.invoke(obj);
        System.out.println(message);
    }
}

在上面的示例中,Demo 类有一个带有一个参数的构造函数和一个返回 message 属性值的 getMessage() 方法。在 Main 类中,使用 Class.forName() 方法获取 Demo 类的类型,然后使用 getConstructor() 方法获取 Demo 类的带有一个字符串参数的构造函数。接着,使用 newInstance() 方法创建一个 Demo 类的实例。最后,使用 getMethod() 方法获取 Demo 类的 getMessage() 方法,然后使用 invoke() 方法调用该方法,并将返回值强制转换为字符串类型。

3.getName、getCanonicalName与getSimpleName的区别?

这三个方法都是在 Class 类中定义的,可以用来获取一个类的名称或规范化名称。在很多情况下,它们的返回值是相同的。但是,在一些特殊情况下,它们的返回值可能会有所不同。

  • getName() 方法返回的是一个类的全限定名,包括包名和类名,例如 "java.lang.String"

  • getCanonicalName() 方法返回的是该类的规范化名称,也就是在所有类型名称上执行一系列规则后的名称,例如 "java.lang.String"

  • getSimpleName() 方法返回的是该类的简单名称,也就是不包括包名的类名,例如 "String"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/354648.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

嵌入式Linux入门级板卡的神经网络框架ncnn移植与测试-米尔i.MX6UL开发板

本篇测评由电子发烧友的优秀测评者“ALSET”提供。 米尔 MYD-Y6ULX-V2 开发板&#xff0c;基于 NXP i.MX6UL/i.MX6UL L处理器&#xff0c;该开发板被米尔称之为经典王牌产品。本次测试目标是在此开发板上进行神经网络框架ncnn的移植与测试开发&#xff0c;测试ncnn在此开发板上…

高可用的“异地多活”架构设计

前言 后台服务可以划分为两类&#xff0c;有状态和无状态。高可用对于无状态的应用来说是比较简单的&#xff0c;无状态的应用&#xff0c;只需要通过 F5 或者任何代理的方式就可以很好的解决。后文描述的主要是针对有状态的服务进行分析。 服务端进行状态维护主要是通过磁盘…

Orin 安装CUDA CUDNN TensorRT Opencv和输入法的环境配置

有两种方法可以安装CUDA环境 第一种方法-用命令按照 在刷机完成的Orin&#xff0c;执行如下命令&#xff1a; sudo apt update sudo apt upgrade sudo apt install nvidia-jetpack -y注释–如果在执行第三行命令&#xff0c;报错的话&#xff0c;先查看nvidia-l4t-apt-so…

初识K8s

概览 k8s 概念和架构从零搭建K8s 集群k8s 核心概念搭建集群监控平台搭建高可用k8s集群集群环境 实际部署项目 k8s 概念和架构 1、K8S概述和特性 概述&#xff1a; k8s是谷歌在2014年开源的容器化集群管理系统使用k8s进行容器化应用部署使用k8s利于应用扩展k8s目标实施让部…

AcWing3416.时间显示——学习笔记

目录 题目 代码 AC结果 思路 关键步骤 题目 3416. 时间显示 - AcWing题库https://www.acwing.com/problem/content/description/3419/ 代码 import java.util.Scanner;public class Main {public static void main(String[] args){Scanner input new Scanner(System.in…

Rust学习入门--【15】Rust 所有权

系列文章目录 Rust 语言是一种高效、可靠的通用高级语言&#xff0c;效率可以媲美 C / C 。本系列文件记录博主自学Rust的过程。欢迎大家一同学习。 Rust学习入门–【1】引言 Rust学习入门–【2】Rust 开发环境配置 Rust学习入门–【3】Cargo介绍 Rust学习入门–【4】Rust 输…

Maven的安装和配置

Maven的安装 1.1Maven是什么&#xff1f; 是阿帕奇的&#xff0c;就是代替原先手动导入jar包的方式 1.官方介绍 视频&#xff1a;百度百科-验证Maven是一款服务于Java平台的自动化构建工具。Maven 作为 Java 项目管理工具&#xff0c;它不仅可以用作包管理&#xff0c;还有许多…

DIDL4_前向传播与反向传播(模型参数的更新)

前向传播与反向传播前向传播与反向传播的作用前向传播及公式前向传播范例反向传播及公式反向传播范例小结前向传播计算图前向传播与反向传播的作用 在训练神经网络时&#xff0c;前向传播和反向传播相互依赖。 对于前向传播&#xff0c;我们沿着依赖的方向遍历计算图并计算其路…

# AutoSar一文概览

1.什么是AutoSar ​ AUTOSAR全称为“AUTomotive Open System ARchitecture”&#xff0c;译为“汽车开放系统体系结构”&#xff1b;AUTOSAR是由 全球各大汽车整车厂、汽车零部件供应商、汽车电子软件系统公司联合建立的一套标准协议、软件架构。 2.为什么汽车行业要定义一个…

DIDL5_数值稳定性和模型初始化

数值稳定性和模型初始化数值稳定性梯度不稳定的影响推导什么是梯度消失&#xff1f;什么是梯度爆炸&#xff1f;如何解决数值不稳定问题&#xff1f;——参数初始化参数初始化的几种方法默认初始化Xavier初始化小结当神经网络变得很深的时候&#xff0c;数值特别容易不稳定。我…

面试题67. 把字符串转换成整数

题目 写一个函数 StrToInt&#xff0c;实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。 首先&#xff0c;该函数会根据需要丢弃无用的开头空格字符&#xff0c;直到寻找到第一个非空格的字符为止。 当我们寻找到的第一个非空字符为正或者负号时&#xf…

密度峰值聚类算法(DPC)

密度峰值聚类算法目录DPC算法1.1 DPC算法的两个假设1.2 DPC算法的两个重要概念1.3 DPC算法的执行步骤1.4 DPC算法的优缺点matlab代码密度计算函数计算delta寻找聚类中心点聚类算法目录 DPC算法 1.1 DPC算法的两个假设 1&#xff09;类簇中心被类簇中其他密度较低的数据点包围…

kubernetes 教程

K8s 安装kubectl 下载kubectl curl -LO "https://dl.k8s.io/release/**$(**curl -L -s https://dl.k8s.io/release/stable.txt**)**/bin/linux/amd64/kubectl" 安装 sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl 验证 kubectl versi…

学习 Python 之 Pygame 开发坦克大战(二)

学习 Python 之 Pygame 开发坦克大战&#xff08;二&#xff09;坦克大战的需求开始编写坦克大战1. 搭建主类框架2. 获取窗口中的事件3. 创建基类4. 初始化我方坦克类5. 完善我方坦克的移动5. 完善我方坦克的显示6. 在主类中加入我方坦克并完成坦克移动7. 初始化子弹类8. 完善子…

(考研湖科大教书匠计算机网络)第五章传输层-第一、二节:传输层概述及端口号、复用分用等概念

获取pdf&#xff1a;密码7281专栏目录首页&#xff1a;【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一&#xff1a;传输层概述&#xff08;1&#xff09;概述&#xff08;2&#xff09;从计算机网络体系结构角度看传输层&#xff08;3&#xff09;传输层意义二&am…

MySQL行转列列转行实例解析

文档准备要求&#xff1a;找出所有的用户没有安装的软件。创建两个表&#xff0c;用户表app_install 和 app表app建表语句&#xff1a;# 创建app表&#xff0c;并插入数据 create table app(id int,app varchar(32)); insert into app(id,app) values (1,微信),(2,QQ),(3,支付宝…

二叉树理论基础知识点

二叉树的种类 在我们解题过程中二叉树有两种主要的形式&#xff1a;满二叉树和完全二叉树 满二叉树 满二叉树&#xff1a;如果一棵二叉树只有度为0的结点和度为2的结点&#xff0c;并且度为0的结点在同一层上&#xff0c;则这棵二叉树为满二叉树。 如图所示&#xff1a; 这…

About Oracle Database Performance Method

bottleneck&#xff08;瓶颈&#xff09;&#xff1a; a point where resource contention is highest throughput(吞吐量)&#xff1a; the amount of work that can be completed in a specified time. response time (响应时间)&#xff1a; the time to complete a spec…

Java 日志简介

目录1、Slf4j2、Log4j3、LogBack4、Logback 优点5、ELK1、Slf4j slf4j 的全称是 Simple Loging Facade For Java&#xff0c;即它仅仅是一个为 Java 程序提供日志输出的统一接口&#xff0c;并不是一个具体的日志实现方案&#xff0c;就比如 JDBC 一样&#xff0c;只是一种规则…

解决:eclipse绿化版Resource注解报Resource cannot be resolved to a type问题

如图&#xff1a; 网上解决教程很多&#xff0c;我的eclipse是绿化版的&#xff0c;不需要安装 解决办法如下&#xff1a; 1、在eclipse中&#xff0c;进入到Window->Preferences->Java->Installed JREs中 默认显示如下&#xff1a; 2、点击Add-->Standard VM--…