第4节:Java基础 - 必知必会(中)

本小节是Java基础篇章的第二小节,主要讲述抽象类与接口的区别,注解以及反射等知识点。

一、抽象类和接口有什么区别

抽象类和接口的主要区别可以总结如下:

  • 抽象类中可以没有抽象方法,JDK8版本开始提供了接口总方法的default实现

  • 抽象类和类一样是单继承的;接口可以实现多个父类

  • 抽象类中可以存在普通的成员变量;接口中的变量必须是static final类型的,必须被初始化,接口中只能有常量,没有变量

    解析

    在Java中,我们用abstract来定义抽象类,通过interface关键字来定义接口。接口和抽象类中都可以定义抽象方法,然后交由其实现类来实现该抽象方法。

    抽象类和接口应该如何选择?分别在什么情况下使用呢?

根据抽象类和接口的不同之处,当我们仅仅需要定义一些抽象方法而不需要其余二外的具体方法或者变量的时候,我们嗯可以使用接口。反之,则需要使用抽象类,因为抽象类中可以有非抽象方法和变量

默认方法

  既然说到了JDK8接口中的方法可以实现,那么我们来看下default方法的具体实现。我们先给出一个接口中的default方法Demo,如下所示:

public interface MyInterface {
// 定义一个已经实现的方法,使用default表明
default void say(String message){
System.out.println("Hello "+message);
}
// 普通的抽象方法
void test();
}

  当一个类实现该接口时,可以继承到该接口中的默认方法,如下所示:

public interface MyInterface {
// 定义一个已经实现的方法,使用default表明
default void say(String message){
System.out.println("Hello "+message);
}
// 普通的抽象方法
void test();
} class MyClass implements MyInterface{
@Override
public void test() {
System.out.println("test...");
}
}
class Main{
public static void main(String[] args) {
MyClass client = new MyClass();
client.test();
client.say("World...");
}
}

  这样的话,大家就会有疑问,如果两个接口中存在同样的默认方法,实现类继承的是哪一个呢?Demo如下:

public interface MyInterface {
// 定义一个已经实现的方法,使用default表明
default void say(String message){
System.out.println("Hello "+message);
}
// 普通的抽象方法
void test();
}
interface MyInterface2{
// 定义一个已经实现的方法,使用default表明
default void say(String message){
System.out.println("[2]-Hello "+message);
}
}
// 此处会编译错误
class MyClass implements MyInterface, MyInterface2{
@Override
public void test() {
System.out.println("test...");
}
}

这个时候,实现类那里会编译错误 .我们有两种处理方式,如下所示:

  • 重写多个接口中的相同的默认方法

  • 在实现类中指定要使用哪个接口中的默认方法

a、重写多个接口中的相同的默认方法

class MyClass implements MyInterface, MyInterface2{
@Override
public void say(String message) {
System.out.println("[Client]-Hello "+message);
}
@Override
public void test() {
System.out.println("test...");
}
}

b、在实现类中指定要使用哪个接口中的默认方法:

class MyClass implements MyInterface, MyInterface2{
// 手动指定哪个默认方法生效
public void say(String message) {
MyInterface.super.say(message);
}
@Override
public void test() {
System.out.println("test...");
}
}

那么JDK8中为什么会出现默认方法呢?

使用接口,使得我们可以面向抽象编程,但是其有一个缺点就是当接口中有改动的时候,需要修改所有的实现类。在JDK8中,为了给已经存在的接口增加新的方法并且不影响已有的实现,所以引入了接口中的默认方法实现。

默认方法允许在不打破现有继承体系的基础上改进接口,解决了接口的修改与现有的实现不兼容的问题。该特性在官方库中的应用是:给java.util.Collection接口添加新方法,如stream()、parallelStream()、forEach()和removeIf()等等。在我们实际开发中,接口的默认方法应该谨慎使用,因为在复杂的继承体系中,默认方法可能引起歧义和编译错误

二、java中的8中基本数据类型及其取值范围

Java种的8种基本数据类型分别是:byte,short,int,long,float,double,char以及boolean。boolean类型的取值为true和false两种,其余每一种基本类型都占有一定的字节,并且拥有着最大值和最小值。比如int的取值范围为 Integer.MIN_VALUE 到 Integer.MAX_VALUE。这个题目的答案,我希望大家可以自己动手输入代码来一一查看以加深记忆。这里给出每种基本类型所占用的字节数:

  • byte:1字节

  • short:2字节

  • int:4个字节

  • long:8字节

  • float:4字节

  • double:8字节

  • char:2字节

  • boolean:Java规范中并没有规定boolean类型所占字节数

解析:

这是一个特别基础的题目,面试时候基本会考察各个基本类型所占的字节数,需要准确记忆与理解。关于取值范围,如果实在记忆有点缺失,可以和面试官说通过哪个字段可以获取到其取值范围也算尚可

三、Java中的元素注解有哪些?

Java中提供了4个元注解,元注解的作用是负责注解其它注解。

@Target

说明注解所修饰的对象范围,关键源码如下:

public @interface Target {
ElementType[] value();
}
public enum ElementType {
TYPE,FIELD,METHOD,PARAMETED,CONSTRUCTOR,LOCAL_VARIABLE,ANNOCATION_TYPE,PACKAGE,TYPE_PARAMETER,TYPE_USE
}

例如,如下的注解使用@Target标注,表明MyAnn注解就只能作用 在类/接口和方法上。

@Target({ElementType.TYPE, ElementType.METHOD}) public @interface MyAnn { }

@Rentention

保留策略定义了该注解被保留的时间长短。关键源码如下:

public @interface Retention { RetentionPolicy value(); } public enum RetentionPolicy { SOURCE, CLASS, RUNTIME }

其中,SOURCE:表示在源文件中有效(即源文件保留);CLASS:表示在class文件中有效(即class保留);RUNTIME:表示在运行时有效(即运行时保留)。例如,@Retention(RetentionPolicy.RUNTIME)标注表示该注解在运行时有效。

@Documented

该注解用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被javadoc此类的工具文档化。Documented是一个标记注解,没有成员。关键源码如下:

public @interface Documented {
}

  

@Inherited

该注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。关键源码如下:

public @interface Inherited {
}

  

解析:

Java中的注解是一个基础知识点,我们在程序中频繁的使用注解。使用注解可以代替配置文件,比如SpringBoot就是提供了大量的注解来代替配置文件,从而极大的方便了Web项目的搭建与开发。那么,我们再来详细阐述下Java中的注解吧。

注解的作用:

代替繁杂的配置文件,简化开发。

何定义一个注解?

定义注解类不能使用class、enum以及interface,必须使用@interface。下边是一个简单的注解定义:

public @interface MyAnn{}

如何定义注解的属性?

public @interface MyAnn {
String value();
int value1();
}
// 使用注解MyAnn,可以设置属性
@MyAnn(value1=100,value="hello")
public class MyClass {
}

  

定义注解时候的value就是属性,看着是一个方法,但我们称它为属性。当为注解指定属性后,那么在使用注解时就必须要给属性赋值了。

四、Java中反射机制

反射机制是指在运行中,对于任意一个类,都能够知道这个类的所有属性和方法。对于任意一个对象,都能够调用它的任意一个方法和属性。即动态获取信息和动态调用对象方法的功能称为反射机制。

反射机制的作用

  • 在运行时判断任意一个对象所属的类

  • 在运行时构造一个类的对象

  • 在运行时判断任意一个类所具有的成员变量和方法

  • 在运行时调用任意一个对象的方法,生成动态代理

    与反射相关的类:

  • Class:表示类,用于获取类的相关信息

  • Field:表示成员变量,用于获取实例变量和静态变量等

  • Method:表示方法,用于获取类中的方法参数和方法类型等

  • Constructor:表示构造器,用于获取构造器的相关参数和类型等

这里我们讲述下如何获取Class类吧,获取Class类有三种基本方式:

(1)通过类名称.class来获取Class类对象:

Class c = int.class;
Class c = int[ ].class;
Class c = String.class

  

(2)通过对象.getClass( )方法来获取Class类对象:

Class c = obj.getClass( );

(3)通过类名称加载类Class.forName( ),只要有类名称就可以得到Class:

Class c = Class.forName(“cn.ywq.Demo”);

接下来,我们给出一个以反射方式来创建对象的Demo:

package com.ywq;

public class Demo1 {
public static void main(String[] args) throws Exception {
String className = "com.ywq.User";
// 获取Class对象
Class clazz = Class.forName(className);
// 创建User对象
User user = (User)clazz.newInstance();
// 和普通对象一样,可以设置属性值
user.setUsername("yangwenqiang");
user.setPassword("19931020"); System.out.println(user);
}
} class User {
private String username;
private String password; public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} @Override
public String toString() {
return "User [username=" + username + ", password=" + password + "]";
}
}

附加

clazz.newInstance()和clazz.new()区别总结如下:

1.构造方法实例化, 会判断实例化的对象的Class是否已经加载,如果没有加载需先加载类,然后初始化类,返回一个实例.

clazz.newInstance()方法必须在类加载完成之后才能调用.也就是说,这一步不会有类加载的步骤.类加载必须在此之前加载完成,否则不能调用该方法.

比如Class.forName(Stirng clazzName)包含加载和连接两个阶段,连接阶段包含:验证,准备,解析三个阶段;

然后初始化类,返回一个实例

2.clazz调用的是无参构造方法,而实例化构造方法使用有参构造方法. 当然需要public修饰. 反正要能访问的到.

3.clazz反射可以用来解耦合,动态的构造实例. 比如IOC控制反转,以及基于接口编程.可以把实现类或者子类,强转为接口类或父。

关于反射这块的详细API接口介绍,建议大家参考官方提供的API接口文档 。

总结

本小节是Java基础篇章的第二小节,本小节中介绍的接口和抽象类的区别,建议大家熟练掌握。注解和反射机制在Java基础中具有一定的难度,希望大家可以多加理解与掌握。

 

第4节:Java基础 - 必知必会(中)的更多相关文章

  1. 第5节:Java基础 - 必知必会(下)

    第5节:Java基础 - 必知必会(下) 本小节是Java基础篇章的第三小节,主要讲述Java中的Exception与Error,JIT编译器以及值传递与引用传递的知识点. 一.Java中的Excep ...

  2. 第3节:Java基础 - 必知必会(上)

    第3节:Java基础 - 必知必会(上) 本篇是基础篇的第一小节,我们从最基础的java知识点开始学习.本节涉及的知识点包括面向对象的三大特征:封装,继承和多态,并且对常见且容易混淆的重要概念覆盖和重 ...

  3. Java面试必知必会(扩展)——Java基础

    float f=3.4;是否正确? 不正确 3.4是双精度,将双精度赋值给浮点型属于向下转型,会造成精度损失: 因此需要强制类型转换: 方式一:float f=(float)3.4 方式二:float ...

  4. Java面试必知必会:基础

    面试考察的知识点多而杂,要完全掌握需要花费大量的时间和精力.但是面试中经常被问到的知识点却没有多少,你完全可以用 20% 的时间去掌握 80% 常问的知识点. 一.基础 包括: 杂七杂八 面向对象 数 ...

  5. 迈向高阶:优秀Android程序员必知必会的网络基础

    1.前言 网络通信一直是Android项目里比较重要的一个模块,Android开源项目上出现过很多优秀的网络框架,从一开始只是一些对HttpClient和HttpUrlConnection简易封装使用 ...

  6. 【SQL必知必会笔记(1)】数据库基础、SQL、MySQL8.0.16下数据库、表的创建及数据插入

    文章目录 1.数据库基础 1.1 数据库(database) 1.2 表(table) 1.3 列和数据类型 1.4 行 1.5 主键 2.什么是SQL 3.创建后续练习所需数据库.表(MySQL8. ...

  7. Java并发必知必会第三弹:用积木讲解ABA原理

    Java并发必知必会第三弹:用积木讲解ABA原理 可落地的 Spring Cloud项目:PassJava 本篇主要内容如下 一.背景 上一节我们讲了程序员深夜惨遭老婆鄙视,原因竟是CAS原理太简单? ...

  8. 必知必会之 Java

    必知必会之 Java 目录 不定期更新中-- 基础知识 数据计量单位 面向对象三大特性 基础数据类型 注释格式 访问修饰符 运算符 算数运算符 关系运算符 位运算符 逻辑运算符 赋值运算符 三目表达式 ...

  9. .NET零基础入门09:SQL必知必会

    一:前言 仿佛到了更进一步的时候了,每一个程序员迟早都会遇到数据存储的问题.我们拿什么来存储程序产生的数据?举例来说,用什么来存储我们的打老鼠游戏每次的成绩呢?选择如下: 1:内存中.缺点,退出游戏, ...

随机推荐

  1. jquery jssdk分享报错解决方法

    jssdk分享报错解决方法 一般都是参数传错了

  2. ARP通信

    ARP:地址解析协议,是根据IP地址获取物理地址的一个TCP/IP协议 简单介绍ARP通信过程: 1.发送端在与接收端进行数据通信转发时的过程: 发送端与接收端进行数据通信之前,需要先知道对端的MAC ...

  3. 在VMware环境下安装CentOS7

    1. 软件准备: 推荐使用VMware,在这里我使用的是VMware15 映像:可以去官网下载,没有的话也可以在下方链接里下载 链接:https://pan.baidu.com/s/1r_7K-UI0 ...

  4. 外行人都能看懂的WebFlux,错过了血亏!

    前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 本文知识点架构: 如果有关注我公众号文章的同学就会发 ...

  5. pdf2eps implement

    Well, I used the command pdftops in the LaTeX distribution such as MiKTeX/TeXLive/CTex to implement ...

  6. java编程思想第四版第八章习题

    第一题 package net.mindview.polymorphism; //基类-自行车 class Cycle{ } //子类-单轮车 class Unicycle extends Cycle ...

  7. dubbo分布式Service不可以创建Error creating bean with name 'XXXXXX'

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'demoService' ...

  8. nyoj 71-独木舟上的旅行(贪心)

    71-独木舟上的旅行 内存限制:64MB 时间限制:3000ms 特判: No 通过数:10 提交数:15 难度:2 题目描述: 进行一次独木舟的旅行活动,独木舟可以在港口租到,并且之间没有区别.一条 ...

  9. Docker解决下载镜像速度慢

    Docker安装好以后要用Docker pull命令下载镜像,但是会出现下载很慢的现象.Docker默认是国外的源,配置国内镜像仓库. 1.cd /etc/docker/路径下 2.编辑daemon. ...

  10. 【Vue | ElementUI】Vue离开当前页面时弹出确认框实现

    Vue离开当前页面时弹出确认框实现 1. 实现目的 在某种业务场景下,用户不允许跳转到其他页面.于是,需要在用户误操作或者是点击浏览器跳转时提示用户. 2. 实现原理 使用路由守卫beforeRout ...