java基础复习

简介: 这是前段时间学长让复习java基础时候发了一个问题的文档,根据问题在网上查阅资料文档总结记录下来的内容(我把问题的文档也放到下面方便查阅)java基础复习开发者客栈-帮助开发者面试的平台-顽强网络 (developers.pub)http://c.biancheng.net/java/10/Java 语言是一种分布式的面向对象语言,具有面向对象、平台无关性、简单性、解释执行、多线程、安全性等很多特点1. 面向对象Java 是一种面向对象的语言,它对对象中的类、对象、继承、封装、多态、接口、包等均有很好的支持。为了简单起见,Java 只支持类之间的单继承,但是可以使用接口来实现多继承

这是前段时间学长让复习java基础时候发了一个问题的文档,根据问题在网上查阅资料文档总结记录下来的内容(我把问题的文档也放到下面方便查阅)

java基础复习

开发者客栈-帮助开发者面试的平台-顽强网络 (developers.pub)

http://c.biancheng.net/java/10/

Java 语言是一种分布式的面向对象语言,具有面向对象、平台无关性、简单性、解释执行、多线程、安全性等很多特点

1. 面向对象

Java 是一种面向对象的语言,它对对象中的类、对象、继承、封装、多态、接口、包等均有很好的支持。为了简单起见,Java 只支持类之间的单继承,但是可以使用接口来实现多继承。

2. 多线程

Java 语言是多线程的,这也是 Java 语言的一大特性,它必须由 Thread 类和它的子类来创建。Java 支持多个线程同时执行,并提供多线程之间的同步机制。任何一个线程都有自己的 run() 方法,要执行的方法就写在 run() 方法体内。

3.java中jvm ,jre,jdk三者有什么区别

Java 语言的开发运行,也离不开 Java 语言的运行环境 JRE。没有 JRE 的支持,Java 语言便无法运行。当然,如果还想编译 Java 程序,搞搞小开发的话,JRE 是明显不够了,这时候就需要 JDK。  

其实啊,JDK 就是 JRE 加上一些常用工具组成的。JDK 不仅能运行已经被编译好了的 Java 程序,还能支持我们编译 Java 程序(JDK=JER+各种工具)。

  • JDK(Java Development Kid,Java 开发开源工具包),是针对 Java 开发人员的产品,是整个 Java 的核心,包括了 Java 运行环境 JRE、Java 工具和 Java 基础类库。
  • JRE(Java Runtime Environment,Java 运行环境)是运行 JAVA 程序所必须的环境的集合,包含 JVM 标准实现及 Java 核心类库。
  • JVM(Java Virtual Machine,Java 虚拟机)是整个 Java 实现跨平台的最核心的部分,能够运行以 Java 语言写作的软件程序。

  • JDK=JRE+多种Java开发工具
  • JRE=JVM+各种类库
  • 这三者的关系是一层层的嵌套关系。JDK>JRE>JVM

4.java初学者容易犯的几个问题

1)大小写问题

2)路径里包含空格的问题

3)main 方法的问题

如果需要用 java 命令直接运行一个 Java 类,这个 Java 类必须包含 main 方法,这个 main 方法必须使用 public 和 static 来修饰,必须使用 void 声明该方法的返回值,而且该方法的参数类型只能是一个字符串数组,而不能是其他形式的参数。对于这个 main 方法而言,前面的 public 和 static 修饰符的位置可以互换,但其他部分则是固定的。  

定义 main 方法时,不要写成 Main 方法,如果不小心把方法名的首字母写成了大写,编译时不会出现任何问题,但运行该程序时将给出如图 2 的错误提示:

这个错误提示找不到 main 方法,因为 Java 虚拟机只会选择从 main 方法开始执行。对于 Main 方法,Java 虚拟机会把该方法当成一个普通方法,而不是程序的入口。  

main 方法里可以放置程序员需要执行的可执行性语句,例如 System.out.println("Hello Java!"),这行语句是 Java 里的输出语句,用于向控制台输岀“Hello Java!”这个字符串内容,输出结束后还输出一个换行符。  

在 Java 程序里执行输岀有两种简单的方式:System.out.print(需要输出的内容) 和 System.out.println (需要输出的内容),其中前者在输出结束后不会换行,而后者在输出结束后会换行。后面会有关于这两个方法更详细的解释,此处读者只能把这两个方法先记下来。

5.String、StringBuffer和StringBuilder类的区别

Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。String 类是不可变类,即一旦一个 String 对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。

StringBuilder 类是 JDK 1.5 新增的类,它也代表可变字符串对象。实际上,StringBuilder 和 StringBuffer 功能基本相似,方法也差不多。不同的是,StringBuffer 是线程安全的,而 StringBuilder 则没有实现线程安全功能,所以性能略高。因此在通常情况下,如果需要创建一个内容可变的字符串对象,则应该优先考虑使用 StringBuilder 类。

总结

String 是 Java 中基础且重要的类,被声明为 final class,是不可变字符串。因为它的不可变性,所以拼接字符串时候会产生很多无用的中间对象,如果频繁的进行这样的操作对性能有所影响。  

StringBuffer 就是为了解决大量拼接字符串时产生很多中间对象问题而提供的一个类。它提供了 append 和 add 方法,可以将字符串添加到已有序列的末尾或指定位置,它的本质是一个线程安全的可修改的字符序列。  

在很多情况下我们的字符串拼接操作不需要线程安全,所以 StringBuilder 登场了。StringBuilder 是 JDK1.5 发布的,它和 StringBuffer 本质上没什么区别,就是去掉了保证线程安全的那部分,减少了开销。  

线程安全:

StringBuffer:线程安全  

StringBuilder:线程不安全  

速度:

一般情况下,速度从快到慢为 StringBuilder > StringBuffer > String,当然这是相对的,不是绝对的。  

使用环境:

操作少量的数据使用 String。  

单线程操作大量数据使用 StringBuilder。  

多线程操作大量数据使用 StringBuffer。

Java正则表达式详解

正则表达式是一个强大的字符串处理工具,可以对字符串进行查找、提取、分割、替换等操作,是一种可以用于模式匹配和替换的规范。一个正则表达式就是由普通的字符(如字符 a~z)以及特殊字符(元字符)组成的文字模式,它用以描述在查找文字主体时待匹配的一个或多个字符串

String 类里也提供了如下几个特殊的方法。  

  • boolean matches(String regex):判断该字符串是否匹配指定的正则表达式。
  • String replaceAll(String regex, String replacement):将该字符串中所有匹配 regex 的子串替换成 replacement。
  • String replaceFirst(String regex, String replacement):将该字符串中第一个匹配 regex 的子串替换成 replacement。
  • String[] split(String regex):以 regex 作为分隔符,把该字符串分割成多个子串。

如果需要匹配这些特殊字符,就必须首先将这些字符转义,也就是在前面添加一个反斜线\

Math的方法

6.Java生成随机数(random()和Random类)

7.Java数字格式化

数字的格式在解决实际问题时使用非常普遍,这时可以使用 DedmalFormat 类对结果进行格式化处理

8.数组的总结

数组操作

1. 比较数组

比较数组元素的个数和对应位置的元素是否相等。

Arrays.equals(arrayA, arrayB);

arrayA 是用于比较的第一个数组,arrayB 是用于比较的第二个数组。  

2. 填充数组

在指定位置进行数值填充。

Arrays.fill(array,value);

array 表示数组,value 表示填充的值。只能使用同一个数值进行填充。  

3. 数组查找

从数组中查询指定位置的元素,或者查询某元素在指定数组中的位置,语法格式如下。  

binarySearch(Object[] a,Object key);

a 表示要搜索的数组,key 表示要搜索的值。  

在数组中指定范围内查找,语法格式如下。

binarySearch(Object[] a,int fromIndex,int toIndex,Object key);

a 表示要进行查找的数组,fromIndex 指定范围的开始处索引(包含开始处),toIndex 指定范围的结束处索引(不包含结束处),key 表示要搜索的元素。  

4. 复制数组

1) copyOf()

Arrays.copyOf(dataType[] srcArray,int length);

srcArray 表示要进行复制的数组,length 表示复制后的新数组的长度  

2) CopyOfRange()

Arrays.copyOfRange(dataType[] srcArray,int startIndex,int endIndex)

srcArray 表示原数组,startIndex 表示开始复制的起始索引,endIndex 表示终止索引。  

3) arraycopy()

System.arraycopy(dataType[] srcArray,int srcIndex,int destArray,int destIndex,int length)

srcArray 表示原数组,srcIndex 表示源数组中的起始索引,destArray 表示目标数组,destIndex 表示目标数组中的起始索引,length 表示要复制的数组长度。  

4) clone()

array_name.clone()

数组排序

Java 数组中有 5 种常见排序方法,分别是:

  1. Arrays.sort()
  2. 冒泡排序
  3. 快速排序
  4. 选择排序
  5. 直接插入

常见问题解答

1. 声明数组需要注意什么?

声明数组时,一定要考虑数组的最大容量,防止容量不够的现象。数组一旦被声明,它的容量就固定了,不容改变。如果想在运行程序时改变容量,就需要用到集合。关于集合我们会在教程后面讲解。  

2. 数组在平时的程序代码中使用是否频繁?

数组有一个缺点,就是一旦声明,就不能改变容量,这个也是其使用频率不高的原因。一般存储数据会使用集合或 Vector 来存储数据,后面我们会讲到。



9.super和this的区别

this 指的是当前对象的引用,super 是当前对象的父对象的引用。下面先简单介绍一下 super 和 this 关键字的用法。

super 关键字的用法:

super 可以用来直接调用父类中的构造方法,使编写代码也更加简洁方便。  

编译器会自动在子类构造方法的第一句加上super();来调用父类的无参构造方法,必须写在子类构造方法的第一句,也可以省略不写。通过 super 来调用父类其它构造方法时,只需要把相应的参数传过去。

  1. super.父类属性名:调用父类中的属性
  2. super.父类方法名:调用父类中的方法
  3. super():调用父类的无参构造方法
  4. super(参数):调用父类的有参构造方法
  5. 如果构造方法的第一行代码不是 this() 和 super(),则系统会默认添加 super()。

this 关键字的用法:

  1. this.属性名:表示当前对象的属性
  2. this.方法名(参数):表示调用当前对象的方法
  3. 当局部变量和成员变量发生冲突时,使用this.进行区分。  

关于 Java super 和 this 关键字的异同,可简单总结为以下几条。  

  1. 子类和父类中变量或方法名称相同时,用 super 关键字来访问。可以理解为 super 是指向自己父类对象的一个指针。在子类中调用父类的构造方法。
  2. this 是自身的一个对象,代表对象本身,可以理解为 this 是指向对象本身的一个指针。在同一个类中调用其它方法。
  3. this 和 super 不能同时出现在一个构造方法里面,因为 this 必然会调用其它的构造方法,其它的构造方法中肯定会有 super 语句的存在,所以在同一个构造方法里面有相同的语句,就失去了语句的意义,编译器也不会通过。
  4. this( ) 和 super( ) 都指的是对象,所以,均不可以在 static 环境中使用,包括 static 变量、static 方法和 static 语句块。
  5. 从本质上讲,this 是一个指向对象本身的指针, 然而 super 是一个 Java 关键字。

10.Java对象类型转换:向上转型和向下转型

将一个类型强制转换成另一个类型的过程被称为类型转换。本节所说的对象类型转换,是指存在继承关系的对象,不是任意类型的对象。当对不存在继承关系的对象进行强制类型转换时,会抛出 Java 强制类型转换(java.lang.ClassCastException)异常

1)向上转型

父类引用指向子类对象为向上转型,语法格式如下:

fatherClass obj = new sonClass();

2)向下转型

与向上转型相反,子类对象指向父类引用为向下转型,语法格式如下:

sonClass obj = (sonClass) fatherClass;

11.异常处理

在 Java 中一个异常的产生,主要有如下三种原因:

  1. Java 内部错误发生异常,Java 虚拟机产生的异常。
  2. 编写的程序代码中的错误所产生的异常,例如空指针异常、数组越界异常等。
  3. 通过 throw 语句手动生成的异常,一般用来告知该方法的调用者一些必要信息。

12.继承

执行顺序:父类静态变量,方法→父类静态代码块→子类静态变量,方法→子类静态代码块→父类非静态代码快→父类构造函数→子类非静态代码快→子类构造函数。注:静态变量,方法按照位置顺序执行。

静态块中的代码按写的顺序首先依次执行,执行于方法前

13.构造方法

特点:

  • 构造方法名与类名相同
  • 构造方法没有返回值 类型,也不写void
  • 构造方法可以重载

构造方法的作用:

  • 在创建对象时,给属性赋初值
  • 构造方法何时使用
  • 构造方法在创建对象时被调用

构造方法的分类:

  • 显示的构造方法和隐式的构造方法
  • 当声明了构造方法时,系统不会提供隐式的默认的无参构造方法\
  • 编译看左边,运行看右边

下面的笔记和题目顺序大致一致

java基础复习总结

一.基础概念和常识

1) JVM vs JDK vs JRE
2) 为什么说 Java 语言“编译与解释并存”?

1. JVM vs JDK vs JRE

  • JDK:Java Development Kit
  • JRE:Java Runtime Environment

JRE就是运行Java字节码的虚拟机。但是,如果只有Java源码,要编译成Java字节码,就需要JDK,因为JDK除了包含JRE,还提供了编译器、调试器等开发工具。

二者关系如下:

┌─    ┌──────────────────────────────────┐

│     │     Compiler, debugger, etc.     │

│     └──────────────────────────────────┘

JDK ┌─ ┌──────────────────────────────────┐

│  │  │                                  │

│ JRE │      JVM + Runtime Library       │

│  │  │                                  │

└─ └─ └──────────────────────────────────┘

┌───────┐┌───────┐┌───────┐┌───────┐

│Windows││ Linux ││ macOS ││others │

└───────┘└───────┘└───────┘└───────┘

JDK(Java Development

Kit)是针对Java开发员的产品,是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。

JRE (Java Runtime Environment)是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。

JVM (Java Virtual

Machine)是Java虚拟机的缩写,是整个java实现跨平台的最核心的部分,能够运行以Java语言写作的软件程序。

三者的关系是JDK包含JRE包含JVM,Java运行步骤:源码—javac编译器—>字节码文件—Java解释器—>机器码文件。

jvm的作用是将字节码文件解释为机器码文件。

源码通过javac编译器转化为字节码文件,字节码文件是一样的。不一样的是jvm,针对不同的系统有不同的 jvm 实现。

总结

JDK是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。JRE是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。JVM是整个java实现跨平台的最核心的部分,能够运行以Java语言写的程序。

2.


2. 为什么说 Java 语言“编译与解释并存”?

编译型语言

会通过编译器将源代码翻译成可执行的机器码

这类语言的执行速度比较快,开发效率低

常见的C,C++,Go,Rust都是编译型语言

解释型语言

会通过解释器将代码一句一句的解释成机器代码然后再去执行

开发效率快,执行速度比较慢

常见的Python,JS,PHP都是解释型语言

编译与解释并存

java具有编译型语言的特征,也具有解释型语言的特征

java程序会经过先编译后解释

先编译生成字节码(.class文件)

再将字节码交给java解释器来解释执行

所以先编译后解释

.java经过javac编译器编译之后得到.class文件->这个就是java文件到虚拟机的中间码->.class文件只有被JVM加载->然后通过解释器-逐行解释执行,这种方式的执行速度会相对比较慢。这是属于解释型语言的特点,中间码即.calss文件只是一个中间码,并不算机器码,所以并不满足编译型语言的特点。然而,有些方法和代码块是经常需要被调用的,也就是所谓的热点代码,后面引进了 JIT 编译器,JIT 属于运行时编译。当 JIT 编译器完成第一次编译后,其会将字节码对应的机器码保存下来,下次可以直接使用。这是属于编译型语言的特点,机器码的运行效率肯定是高于 Java 解释器的。这也解释了我们为什么经常会说 Java 是编译与解释共存的语言。

二.基本语法

  1. 1) 注解
  2. 2) 字符型常量和字符串常量
  3. 3) 标识符和关键字的区别
  4. 4) 泛型,类型擦除
  5. 5) ==和equals()
  6. 6)  hashCode() 与 equals() 等

Java注解

是一个很重要的知识点,用于对代码进行说明,可以对包、类、接口、字段、方法参数、局部变量等进行注解。掌握好Java注解有利于学习框架底层实现。

1、Java自带的标准注解

包括@Override、@Deprecated、@SuppressWarnings等,使用这些注解后编译器就会进行检查。

2、元注解

元注解是用于定义注解的注解,包括@Retention、@Target、@Inherited、@Documented、@Repeatable 等。  

元注解也是Java自带的标准注解,只不过用于修饰注解,比较特殊。

java中字符型常量和字符串常量的区别

1.形式上

字符常量 是单引号(‘’)引起的一个字符,字符串常量 是双引号引起的若干个字符

2.含有上

字符常量相当于一个整形值(ASCll值),可以参与表达式的运算。字符串常量代表一个地址值(该字符串在内存中存放的位置)

3.占内存大小

字符常量占两个字节,字符串常量若干个字节(至少一个字符结束标志)

1) 标识符和关键字的区别

Java标识符和关键字的区别

一、主体不同

关键字属于保留字,是整个语言范围内预先保留的标识符。一般标识符是用户编程时使用的名字,用于给变量、常量、函数、语句块等命名,以建立起名称与使用之间的关系。

二、特点不同

关键字不能声明与关键字同名的标识符。一般标识符由字母和数字以及其它字符构成。

三、规则不同

关键字经过预处理后,关键字从预处理记号(preprocessing-token)中区别出来,剩下的标识符作为记号(token),用于声明对象、函数、类型、命名空间等。一般标识符长度是由机器上的编译系统决定的,一般的限制为8字符。

关键字

对编译器有特殊意义的固定单词,不能在程序中做其他目的使用。关键字具有专门的意义和用途,和自定义的标识符不同,不能当作一般的标识符来使用

Java 语言按其用途划分为如下几组,这些关键字不能作为变量名、类名和方法名来使用!!(注意:关键字一律用小写字母标识)

1、用于数据类型:boolean、byte、char、 double、 float、int、long、new、short、void、instanceof。

2、用于语句:break、case、 catch、 continue、 default 、do、 else、 for、 if、return、switch、try、 while、 finally、 throw、this、 super。

3、用于修饰:abstract、final、native、private、 protected、public、static、synchronized、transient、 volatile。

4、用于方法、类、接口、包和异常:class、 extends、 implements、interface、 package、import、throws。

5、还有些关键字,如 future、 generic、 operator、 outer、rest、var等都是Java保留的没有意义的关键字。

6、另外,Java还有3个保留字:goto、const、null。它们不是关键字,而是文字。包含Java定义的值。和关键字一样,它们也不可以作为标识符使用。

标识符

1、标识符由数字(0~9)和字母(A~Z 和 a~z)、美元符号($)、下划线(_)以及 Unicode 字符集中符号大于 0xC0 的所有符号组合构成(各符号之间没有空格)。

2、标识符的第一个符号为字母、下划线和美元符号,后面可以是任何字母、数字、美元符号或下划线。

标识符的分类

1、关键字是有特殊含义的标识符,如 true、false 表示逻辑的真假。

2、用户自定义标识符是由用户按标识符构成规则生成的非保留字的标识符,如 abc 就是一个标识符。


泛型,类型擦除

  1. 泛型方法不能使用基本数据类型作为参数。
  2. 使用泛型进行编程可以提高程序安全性以及可读性。
  3. 泛型只存在于编译期间。
  4. 通过使用通配符可以放宽对参数的限制增加程序灵活性。

1 泛型通配符

1.1 无边界通配符 <?>

1.2 固定上边界的通配符 <? extends E>

对于上限通配符需要注意的一点就是使用上限通配符只能从结构中获取值而不能将值放入结构中

1.3 固定下边界的通配符<? super E>

对于下限通配符同样需要注意的一点就是使用下限通配符只能将值放入结构中或者将读取结果转换为Object

总结

  1. 如果要从结构中获取值,使用上限通配符;
  2. 在将值放入结构中时,使用下限通配符。
  3. 可以为通配符指定上限,也可以指定下限,但不能同时指定两者。

反编译命令 javap -c [Class名称] 就可以编译class文件。

1、泛型不是协变的

协变:能在使用父类型的场景中改用子类型

逆变:能在使用子类型的场景中改用父类型

不变:不能做到以上两点

2 泛型的特性所引起的问题

泛型类型变量不能是基本数据类型

因为当类型擦除后会变为Object等引用类型,因此基本数据类型不能用于定义泛型类型变量。

使用instanceof注意点

instanceof 是用来测试一个对象是否为一个类的实例,而对于泛型在类型擦除后会变为Object等引用类型,因此instanceof检测和类型转换工作只对原始类型进行.

泛型在静态方法和静态类中的问题

泛型类中的静态方法和静态变量不能使用泛型类所声明的泛型类型参数,因为泛型类中的泛型参数的实例化是在定义对象的时候指定的,而静态变量和静态方法不需要使用对象来调用,因此对象没有创建也就无法确定这个泛型参数是何种类型。另外由于类型擦除的原因,实际上多个泛型方法只存在一个对应的原始类,因此静态变量在这多个泛型类实例之间是共享的。

不能创建一个泛型类型的实例

没有泛型数组由于数组是协变的加上泛型最终会被类型擦除,因此泛型数组违背了泛型的设计初衷是被禁止的

Java泛型实际上是“伪泛型”,它只是在编译期存在当程序到运行时则会被Java虚拟机进行类型擦除,同时Java虚拟机通过桥接的方式将编译期和运行期的程序(泛型类和原始类)连接了起来,从而实现了泛型的整个过程。另外对于Java泛型的许多限制都可以通过类型擦除和泛型的设计初衷来解释(将可能出现的运行时异常移至编译其解决)。

==和equals()

一、对字符串而言,==和equals()的区别

  • "==" 比较的是两个对象的引用(内存地址)是否相同,也用来比较两个基本数据类型的变量值是否相等。
  • equals() 比较的是两个对象的值(内容)是否相同。
  • 对于==:在简单类型中(int等),这能使用该方法进行比较,这种类型没有equals方法,int的值是存在栈中的,==比较的是栈的内容是否相同。在String类型中,比较特殊,用String=“”;这种进行赋值时,两个相同的值用==比较也是相同的。但是用new String(),赋值就不相同。说明String=“”时,java会检查在堆中是否由相同的值,如果有,把新对象的地址也同老对象的地址赋为相同,因此==比较会相同(“”存储在常量区内存中)。但是new String()开辟的就是两个栈,因此用==比较不会相同。对于包装类,如Integer num=127;时,进行自动装箱操作。如果数值在-128-127会有缓存,此时==是相同的;如果数值不在-128~127之间,则==不相同。
  • 对于equals:当时String类型或者是包装类(如Integer),比较的就是堆中的值。对于用户自定义的普通类,equals比较的内存的首地址,这时候和==是一样的,即比较两边指向的是不是同一个对象。

关于hashcode,我们一定要知道一个口诀:

  • hashcode相等,两个对象不一定相等,需要通过equals方法进一步判断;
  • hashcode不相等,两个对象一定不相等;
  • equals方法为true,则hashcode肯定一样;
  • equals方法为false,则hashcode不一定不一样

hashCode()与 equals()

hashCode()和equals()都是Object类中的方法

(1).如果类中不重写方法:

hashCode():属于本地方法,返回的是对象的哈希码值,也称为散列码,实际返回的是一个int的整数。

equals():用来比较两个对象的地址值是否相等

(2)如果类中重写方法:  

hashCode():返回的是根据对象的成员变量,计算出的一个整数  

通过hashCode()和equals()搭配使用比较对象是否相等,是如何提高效率的?

问题:对于一个对象中有大量的成员信息,用equals比较会降低效率

解决:可以先通过hashCode()进行比较,如果不相同则两个对象一定不同,如果相同,再通过eauqls()进行比较,这样既可以判断对象是否相同,又可以提高效率

通过hashCode()和equals()搭配使用比较对象是否相等,是如何提高效率的?

问题:对于一个对象中有大量的成员信息,用equals比较会降低效率

解决:可以先通过hashCode()进行比较,如果不相同则两个对象一定不同,如果相同,再通过eauqls()进行比较,这样既可以判断对象是否相同,又可以提高效率

  1. 基本数据类型

1) 基本数据类所占字节数

2) 自动装箱和拆箱

3) 数据类型的封装类,以及中间的区别

Java基本数据类型及所占字节大小

一、Java基本数据类型

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

分为4类:整数型、浮点型、布尔型、字符型。

整数型:byte、short、int、long

浮点型:float、double

布尔型:boolean

字符型:char

二、各数据类型所占字节大小

1个字节8位

  计算机的基本单位:bit .  一个bit代表一个0或1

byte:1byte = 8bit     1个字节是8个bit

short:2byte

int:4byte

long:8byte

float:4byte

double:8byte

boolean:1byte

char:2byte

————————————————


自动拆箱和装箱

什么是自动装箱拆箱?

装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。

Java基本数据类型与封装类的区别

1.基本数据类型是值传递,封装类是引用传递

2.基本数据类型是存放在栈中的,而封装类是存放于堆中的

3.基本数据类型初始值如:int=0,而封装类Integer=null

4.集合中添加的元素一定是封装类引用数据类型

5.声明基本数据类型不需要实例化可直接赋值,而封装类必须申请一个存储空间实例化才可赋值。

————————————————

三.方法

1) 方法的几种类型

2) 什么是返回值

3) 静态方法的特殊性

4) 实例方法以及和静态方法的区别

1.java中方法的分类和性质

1.无参数无返回值的方法(只执行方法体)

2.无参数有返回值的方法(执行完方法后,需接收返回的数据)

3.有参数无返回值的方法(访问方法时,需传入指定数据类型的值)

4.有参数有返回值的方法(访问方法时,需传入指定数据类型的值,执行完方法后,需接收返回的数据)

形参(形式参数):定义方法时,指定的参数,用于接收实参数据,也就是在写方法代码的时候,我们指定的参数。实参(实际参数):访问方法时,传入的实际数据。

构造方法:

1.构造方法又称为构造器,是用于构建对象的,和对象的关系相当于模具和产品,构造方法会确定构造某些对象的基本属性和规则。

2.结合new关键字进行创建对象的时候使用

3.不能被对象显示的调用,构造方法是用来构造对象的,不能被对象调用,好比模具和产品,构造方法就是模具,对象就是产品。

4.方法名必须和类名一样,构造方法的方法名必须和当下的类名一模一样(包括字母大小写)。

5.无返回值,也不用加void。构造方法是默认无返回值的方法,也不需要专门加void表示无返回值。

6.当类的定义者(就是我们写代码的人),未提供构造方法时,系统默认提供一个无参数的构造方法。

7.当类的定义者(就是我们写代码的人),一旦提供了构造方法,系统就不再提供默认的构造方法。

————————————————

2.返回值:

普通类的情况下,就是你在定义java方法时,必需要定义一个返回值类型或者使用void占位符占位,然后在方法体末端return一个返回值,需要与定义时候的返回值类型一致,然后在调用此方法时,就会把返回值传输到调用处。

3. 静态方法的特殊性

静态成员随着类的加载而加载;

静态成员优先于对象存在;

静态成员被所有对象所共享;

静态成员多了一个中调用方式,可以被类名直接调用。

利:

对对象的共享数据进行单独空间的存储,节省空间,没有必要每一个对象中都存储一份;

可以直接被类名调用。

弊:

生命周期过长;

访问出现局限性,只能访问静态。

4.简述静态方法和实例方法的区别

1.静态方法在编译时就加载了,而实例方法是实例化后加载,在调用静态方法时还没实例化,所以静态方法不能调用实例化方法。

2.静态方法可以直接类名.方法名或者对象名.方法名调用;实例方法只能实例化后,通过对象名.方法名调用。

3.静态方法只能调用类中静态属性和静态方法,不能调用类中实例属性和实例方法;实例方法可以调用静态属性和静态方法,也可以调用实例属性和实例方法。

————————————————

1) 值传递和引用传递的区别

一、值传递:是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

对于基本数据类型的参数,形式参数的改变,不影响实际参数的值。

二、引用传递:是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

对于引用类型的参数传递,形式参数的改变,影响实际参数的值。

1) 重载和重写

Java方法重载

Java 允许同一个类中定义多个同名方法,只要它们的形参列表不同即可。如果同一个类中包含了两个或两个以上方法名相同的方法,但形参列表不同,这种情况被称为方法重载(overload)。

方法重载的要求是两同一不同:同一个类中方法名相同,参数列表不同。至于方法的其他部分,如方法返回值类型、修饰符等,与方法重载没有任何关系。

Java方法重写

在子类中如果创建了一个与父类中相同名称、相同返回值类型、相同参数列表的方法,只是方法体中的实现不同,以实现不同于父类的功能,这种方式被称为方法重写(override),又称为方法覆盖。当父类中的方法无法满足子类需求或子类具有特有功能的时候,需要方法重写。

在重写方法时,需要遵循下面的规则:

  • 参数列表必须完全与被重写的方法参数列表相同。
  • 返回的类型必须与被重写的方法的返回类型相同(Java1.5 版本之前返回值类型必须一样,之后的 Java 版本放宽了限制,返回值类型必须小于或者等于父类方法的返回值类型)。
  • 访问权限不能比父类中被重写方法的访问权限更低(public>protected>default>private)。
  • 重写方法一定不能抛出新的检査异常或者比被重写方法声明更加宽泛的检査型异常。例如,父类的一个方法声明了一个检査异常 IOException,在重写这个方法时就不能抛出 Exception,只能拋出 IOException 的子类异常,可以抛出非检査异常。

另外还要注意以下几条:  

  • 重写的方法可以使用 @Override 注解来标识。
  • 父类的成员方法只能被它的子类重写。
  • 声明为 final 的方法不能被重写。
  • 声明为 static 的方法不能被重写,但是能够再次声明。
  • 构造方法不能被重写。
  • 子类和父类在同一个包中时,子类可以重写父类的所有方法,除了声明为 private 和 final 的方法。
  • 子类和父类不在同一个包中时,子类只能重写父类的声明为 public 和 protected 的非 final 方法。
  • 如果不能继承一个方法,则不能重写这个方法。

一、重载和重写的概念:

重载的概念 :

在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数 类型不同即可。

重写的概念:

在子类中可以根据需要对从父类中继承来的方法进行改造,也称 为方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。

二、重载和重写的特点:

重载的特点:

与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或参数类 型)。调用时,根据方法参数列表的不同来区别。

重写的特点:

1.子类重写的方法必须和父类被重写的方法具有相同的方法名称、参数列表 。

2.子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型 (返回类型为类)。

3.子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限 。

4.子类不能重写父类中声明为private权限的方法 。

5.子类方法抛出的异常不能大于父类被重写方法的异常 (父类异常的子类)。

———————————————

区别:

重写,overriding,是指在继承的情况下,子类中定义了与父类中具有相同型构的新方法,也就是子类重写了父类的方法。

重载,overloading,是在同一个类中,定义了一个以上具有相同名称,但是有着不同型构的方法,在同一个类中是不允许定义多于一个具有相同型构的方法的。

构造器也是可以重载的,实际上,构造器就是一个方法,构造器的名称就是方法的名称。

———————————————

深拷贝和浅拷贝

概念:

浅拷贝 :只复制指向某个对象的指针,而不复制对象本身,相当于是新建了一个对象,该对象复制了原对象的指针,新旧对象还是共用一个内存块

深拷贝:是新建一个一模一样的对象,该对象与原对象不共享内存,修改新对象也不会影响原对象

  1. 面向对象

1) 面向对象和面向过程

2) 成员变量与局部变量的区别有哪些?

3) 对象实体和对象引用的区别

4) 构造方法的作用,特点

5) 三大特性

面向对象和面向过程

优缺点对比

面向过程:

优点:效率高,因为不需要实例化对象。

缺点:耦合度高,扩展性差,不易维护(例如:每个步骤都要有,不然就不行)

面向对象:

优点:耦合低(易复用),扩展性强,易维护,由于面向对象有封装、继承、多态性的特点,可以设计出低耦合的系统,使系统更加灵活、更加易于维护。

缺点:效率比面向过程低。

————————————————

成员变量与局部变量的区别有哪些?

类中定义的变量是成员变量,而方法中定义的变量是局部变量

1.从语法形式上看,成员变量属于类,而局部变量是在方法中定义的变量或是方法的参数。

成员变量可被修饰符修饰,而局部变量则不能被访问控制修饰符及static所修饰;成员变量和局部变量 都可以被final所修饰。

2.从变量在内存中的储存方式上看,成员变量是对象的一部分,而对象是存在于堆内存的,而局部变量 是存在于栈内存的。

3.从变量在内存中的生存时间上看,成员变量是对象的一部分,而对象是存在于堆内存的,而局部变量是存在于栈内存的。

4.成员变量如果没有被赋初值,则会自动以类型的默认值赋值(例外:被final修饰但没有被static修饰的成员变量必须显式地赋值);而局部变量则不会自动赋值,必须显式地赋值后才能使用。

———————————————

java中对象实体与对象的引用有何不同?

对象实体:就是类的这时体现,每个对象都是独立的内存。  

引用就是表示的对象所在内存的位置。其实就是对象的线索。

对象引用的目的地才是对象的实体。

1) 构造方法的作用,特点

1.构造方法的定义与说明

构造方法 : 用来初始化对象的方法

(1)  构造方法名与类名相同 , 且没有返回值,且不需要使用void修饰 。

(2)  作用:在构造方法中为创建的对象初始化赋值,

(3)  在创建一个对象的时候,至少要调用一个构造方法。

(4) 每个类都有构造方法。如果没有显式地为类定义构造方法,Java将会为该类提供一个默认构造方法,但是只要在一个Java类中定义了一个构造方法后,默认的无参构造方法即失效。

我们说构造方法是用来初始化对象的,那么它是怎样去初始化的呢,回想我们创建对象的语法

例 : Car car= new Car();

我们可以看到new关键字右边的这一块 ,这其实就是调用了Car类的构造方法来创建此对象的

2.构造方法的声明与使用

构造方法也分为有参和无参的,如果没有显示的定义构造方法,默认是无参的

构造方法之所以可以分为有参和无参,原因就是方法是可以去重载的

当然我们也可以去为一个类设计更多的构造方法,参数不同即可

1) 三大特性

java三大特性:1、封装,是指隐藏对象的属性和实现细节,仅对外提供公共访问方式;2、继承,从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力;3、多态,一个方法可以有多种实现版本,即“一种定义, 多种实现”。

封装(Encapsulation) : 

封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

好处:

  • 将变化隔离。
  • 便于使用。
  • 提高重用性。
  • 提高安全性。
  • 封装原则:
  • 将不需要对外提供的内容都隐藏起来。
  • 把属性都隐藏,提供公共方法对其访问 。

private关键字:

  • 是一个权限修饰符。
  • 用于修饰成员(成员变量和成员函数)
  • 被私有化的成员只在本类中有效。

继承

Java 不支持多继承,只允许一个类直接继承另一个类,即子类只能有一个直接父类,

使用继承的注意点:

  1. 子类一般比父类包含更多的属性和方法。
  2. 父类中的 private 成员在子类中是不可见的,因此在子类中不能直接使用它们。
  3. 父类和其子类间必须存在“是一个”即“is-a”的关系,否则不能用继承。但也并不是所有符合“is-a”关系的都应该用继承。例如,正方形是一个矩形,但不能让正方形类来继承矩形类,因为正方形不能从矩形扩展得到任何东西。正确的继承关系是正方形类继承图形类。
  4. Java 只允许单一继承(即一个子类只能有一个直接父类),C++ 可以多重继承(即一个子类有多个直接父类)。

继承的优缺点

在面向对象语言中,继承是必不可少的、非常优秀的语言机制,它有如下优点:  

  1. 实现代码共享,减少创建类的工作量,使子类可以拥有父类的方法和属性。
  2. 提高代码维护性和可重用性。
  3. 提高代码的可扩展性,更好的实现父类的方法。

自然界的所有事物都是优点和缺点并存的,继承的缺点如下:  

  1. 继承是侵入性的。只要继承,就必须拥有父类的属性和方法。
  2. 降低代码灵活性。子类拥有父类的属性和方法后多了些约束。
  3. 增强代码耦合性(开发项目的原则为高内聚低耦合)。当父类的常量、变量和方法被修改时,需要考虑子类的修改,有可能会导致大段的代码需要重构。

Java多态性:Java什么是多态?

多态性是面向对象编程的又一个重要特征,它是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义

对面向对象来说,多态分为编译时多态和运行时多态。其中编译时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的方法。通过编译之后会变成两个不同的方法,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是大家通常所说的多态性。

Java 实现多态有 3 个必要条件:继承、重写和向上转型。

  • 继承:在多态中必须存在有继承关系的子类和父类。
  • 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
  • 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。


3.反射

1) 什么是反射

2) 优缺点

3) 使用场景

什么是反射?

反射就是Reflection,Java的反射是指程序在运行期可以拿到一个对象的所有信息。

正常情况下,如果我们要调用一个对象的方法,或者访问一个对象的字段,通常会传入对象实例

一个类在内存中只有一个Class对象

一个类被加载后,类的整个结构都会被封装在Class对象中

如何获取一个classClass实例?有三个方法:

方法一:直接通过一个class的静态变量class获取:

方法二:如果我们有一个实例变量,可以通过该实例变量提供的getClass()方法获取:

方法三:如果知道一个class的完整类名,可以通过静态方法Class.forName()获取:

JVM为每个加载的classinterface创建了对应的Class实例来保存classinterface的所有信息;

获取一个class对应的Class实例后,就可以获取该class的所有信息;

通过Class实例获取class信息的方法称为反射(Reflection);

JVM总是动态加载class,可以在运行期根据条件来控制加载class。

Java的反射API提供的Field类封装了字段的所有信息:

通过Class实例的方法可以获取Field实例:getField()getFields()getDeclaredField()getDeclaredFields()

通过Field实例可以获取字段信息:getName()getType()getModifiers()

通过Field实例可以读取或设置某个对象的字段,如果存在访问限制,要首先调用setAccessible(true)来访问非public字段。

通过反射读写字段是一种非常规方法,它会破坏对象的封装。

  1. I\O流

1) 序列化和反序列化的作用

2) 键盘输入的实现方式

3) 避免序列化的方法

4) 字节流和字符流

序列化和反序列化的作用

  • 序列化:把对象转换为字节序列的过程称为对象的序列化.
  • 反序列化:把字节序列恢复为对象的过程称为对象的反序列化.

序列化是指把一个Java对象变成二进制内容,本质上就是一个byte[]数组。

为什么要把Java对象序列化呢?

因为序列化后可以把byte[]保存到文件中,或者把byte[]通过网络传输到远程,这样,就相当于把Java对象存储到文件或者通过网络传输出去了。

有序列化,就有反序列化,即把一个二进制内容(也就是byte[]数组)变回Java对象。有了反序列化,保存到文件中的byte[]数组又可以“变回”Java对象,或者从网络上读取byte[]并把它“变回”Java对象。

————————————————

所以序列化和反序列化的作用是:

1、把对象转成JSON、xml 的时候,往往这些接口、方法 都实现了序列化,因为网络传输也是一个二进制的过程,需要进行转换

所以只要我们对内存中的对象进行持久化或网络传输, 这个时候都需要序列化和反序列化.

2、还有一个作用就是把对象的字节序列永久地保存到硬盘上 ,比如通过mybatis可持久化到MySQL,也是实现了序列化的。

————————————————

序列化最重要的作用:在传递和保存对象时.保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。

反序列化的最重要的作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。

总结:核心作用就是对象状态的保存和重建。(整个过程核心点就是字节流中所保存的对象状态及描述信息)

————————————————

序列化的其他特性

1、static 属性不会被序列化

2、transient 修饰的属性,也不会被序列化

二、Java实现序列化和反序列化的过程

1、实现序列化的必备要求:

只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列。(不是则会抛出异常)

2、JDK中序列化和反序列化的API:

①java.io.ObjectInputStream:对象输入流。

该类的readObject()方法从输入流中读取字节序列,然后将字节序列反序列化为一个对象并返回。

②java.io.ObjectOutputStream:对象输出流。

该类的writeObject(Object obj)方法将将传入的obj对象进行序列化,把得到的字节序列写入到目标输出流中进行输出。

3、实现序列化和反序列化的三种实现:

①若Student类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化。

ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。

ObjcetInputStream采用默认的反序列化方式,对Student对象的非transient的实例变量进行反序列化。

②若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。

ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。

ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化。

③若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。

ObjectOutputStream调用Student对象的writeExternal(ObjectOutput out))的方法进行序列化。

ObjectInputStream会调用Student对象的readExternal(ObjectInput in)的方法进行反序列化。

三、序列化和反序列化的注意点:

①序列化时,只对对象的状态进行保存,而不管对象的方法。

②当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口。

③当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化。

④并非所有的对象都可以序列化,至于为什么不可以,有很多原因了,比如:

安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行RMI传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;

资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现;

⑤声明为static和transient类型的成员数据不能被序列化。因为static代表类的状态,transient代表对象的临时数据。

⑥序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。为它赋予明确的值。显式地定义serialVersionUID有两种用途。

在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID。

在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

⑦Java有很多基础类已经实现了serializable接口,比如String,Vector等。但是也有一些没有实现serializable接口的。

⑧如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存!这是能用序列化解决深拷贝的重要原因。

————————————————

键盘输入的实现方式

  • System.in和System.out方法
  • * 缺点一: 该方法能获取从键盘输入的字符,但只能针对一个字符的获取 * 缺点二: 获取的只是char类型的。如果想获得int,float等类型的输入,比较麻烦。

  • InputStreamReader和BufferedReader方法  
  • 优点: 可以获取键盘输入的字符串  
  • 缺点: 如何要获取的是int,float等类型的仍然需要转换
  • Scanner类中的方法  
  • 优点一: 可以获取键盘输入的字符串  
  • 优点二: 有现成的获取int,float等类型数据,非常强大,也非常方便;

避免序列化的方法

方式一:transient 关键字

对于不想进行序列化的变量,使用 transient 关键字修饰。

transient 关键字的作用是:

阻止实例中那些用此关键字修饰的的变量序列化;  

当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。  

transient 只能修饰变量,不能修饰类和方法。

使用 transient 来描述字段,将不能被序列化和反序列化'

方式二:@Expose注解

当你不需要完全序列化model字段时,我们就可以使用 @Expose 来解决。

@Expose 默认有两个属性:serialize 和 deserialize,默认值都为 true,如果你给字段设置了 @Expose 注解,但是没有设置serialize 和 deserialize,那 model 的字段都将会输出。

什么是字节流,什么是字符流

字节流: 它处理单元为1个字节(byte),操作字节和字节数组,存储的是二进制文件,如果是音频文件、图片、歌曲,就用字节流好点(1byte = 8位);

字符流: 它处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,如果是关系到中文(文本)的,用字符流好点(1Unicode = 2字节 = 16位);

所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列。

字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串; 2. 字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。

字节流是最基本的,所有的InputStrem和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的 但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的encode来处理,也就是要进行字符集的转化 这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联 在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而造成的

————————————————

最简单的区分字节流和字符流

万物皆文件,那就将文件在记事本里面打开,如果打开后能看的懂的就是字符流,如果看不懂那就是字节流

  • 字符流是以Reader,Writer结尾的
  • 字符节流是以InputStream或OutputStream结尾的
  • 字符流是以Reader,Writer结尾的
  • 字符节流是以InputStream或OutputStream结尾的

什么是缓存区?

定义:缓存区相当于缓存,它是存在内存中的

写操作:

没有使用缓存区:CPU读取每个字节之后直接操作磁盘(性能比较底)进行写完,写操作的瓶颈就会出现,因为每个字节都会操作一次磁盘

使用缓冲区:那么每次会将字符放入缓存区(内存),等缓冲区满了之后,才一次性写入磁盘

因为内存的操作速度远远大于磁盘,因此带缓冲区的输入流和输出流实现的效率就非常高(比如扔垃圾,一次性扔完和一次次扔肯定消耗的时间是有很大差距的)

————————————————

5.1.普通的字符流操作

在程序中一个字符等于两个字节,那么java提供了Reader、Writer两个专门操作字符流的类。

字符输出流:Writer。  

字符输入流:Reader

字节流操作的基本单元是字节;字符流操作的基本单元为Unicode码元。

字节流在操作的时候本身不会用到缓冲区的,是与文件本身直接操作的;而字符流在操作的时候使用到缓冲区的。

所有文件的存储都是字节(byte)的存储,在磁盘上保留的是字节。

在使用字节流操作中,即使没有关闭资源(close方法),也能输出;而字符流不使用close方法的话,不会输出任何内容

————————————————

io流

IO是指Input/Output,即输入和输出。以内存为中心:

  • Input指从外部读入数据到内存,例如,把文件从磁盘读取到内存,从网络读取数据到内存等等。
  • Output指把数据从内存输出到外部,例如,把数据从内存写入到文件,把数据从内存输出到网络等等。

为什么要把数据读到内存才能处理这些数据?

因为代码是在内存中运行的,数据也必须读到内存,最终的表示方式无非是byte数组,字符串等,都必须存放在内存里。

在Java中,InputStream代表输入字节流,OuputStream代表输出字节流,这是最基本的两种IO流

IO流是一种流式的数据输入/输出模型:

  • 二进制数据以byte为最小单位在InputStream/OutputStream中单向流动;
  • 字符数据以char为最小单位在Reader/Writer中单向流动。

Java标准库的java.io包提供了同步IO功能:

  • 字节流接口:InputStream/OutputStream
  • 字符流接口:Reader/Writer

File对象有3种形式表示的路径,一种是getPath(),返回构造方法传入的路径,一种是getAbsolutePath(),返回绝对路径,一种是getCanonicalPath,它和绝对路径类似,但是返回的是规范路径。

ile对象既可以表示文件,也可以表示目录。特别要注意的是,构造一个File对象,即使传入的文件或目录不存在,代码也不会出错,因为构造一个File对象,并不会导致任何磁盘操作。只有当我们调用File对象的某些方法的时候,才真正进行磁盘操作。

例如,调用isFile(),判断该File对象是否是一个已存在的文件,调用isDirectory(),判断该File对象是否是一个已存在的目录:

File对象获取到一个文件时,还可以进一步判断文件的权限和大小:

  • boolean canRead():是否可读;
  • boolean canWrite():是否可写;
  • boolean canExecute():是否可执行;
  • long length():文件字节大小。

对目录而言,是否可执行表示能否列出它包含的文件和子目录。

创建和删除文件

当File对象表示一个文件时,可以通过createNewFile()创建一个新文件,用delete()删除该文件:

有些时候,程序需要读写一些临时文件,File对象提供了createTempFile()来创建一个临时文件,以及deleteOnExit()在JVM退出时自动删除该文件。

遍历文件和目录

当File对象表示一个目录时,可以使用list()listFiles()列出目录下的文件和子目录名。listFiles()提供了一系列重载方法,可以过滤不想要的文件和目录:

  1. 新特性

1) Java8的新特性

2) Streams流

3) Lambda表达式

Java8新特性

  • 速度更快
  • 代码更少(增加了新的语法:Lambda表达式)
  • 强大的 Stream API
  • 便于并行
  • 最大化减少空指针异常:Optional
  • Nashorn引擎,允许在JVM上运行JS应用

Lambda 表达式:在Java 8 语言中引入的一种新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符 或箭头操作符。它将 Lambda 分为两个部分:

左侧:指定了 Lambda 表达式需要的参数列表 (其实就是接口中的抽象方法的形参列表)

右侧:指定了 Lambda 体,是抽象方法的实现逻辑,(其实就是重写的抽象方法的方法体)

————————————————

->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略

->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字

Lambda表达式的本质:作为函数式接口的实例

如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。

以前用匿名实现类表示的现在都可以用Lambda表达式来写。

————————————————

类型推断

在Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”。

————————————————

什么是 Stream

Stream到底是什么呢?是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

“集合讲的是数据,Stream讲的是计算!”

注意:

①Stream 自己不会存储元素。

②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

————————————————

5.3 Stream创建方式

创建 Stream方式一:通过集合

Java8 中的 Collection 接口被扩展,提供了两个获取流

的方法:

default Stream stream() : 返回一个顺序流

default Stream parallelStream() : 返回一个并行流

————————————————

创建 Stream方式二:通过数组

Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:

static Stream stream(T[] array): 返回一个流

重载形式,能够处理对应基本类型的数组:

public static IntStream stream(int[] array)

public static LongStream stream(long[] array)

public static DoubleStream stream(double[] array)

————————————————

创建 Stream方式三:通过Stream的of()

可以调用Stream类静态方法 of(), 通过显示值创建一个流。它可以接收任意数量的参数。

  • public static Stream of(T… values) :返回一个流

可以使用静态方法 Stream.iterate() 和 Stream.generate(),创建无限流。

迭代

public static Stream iterate(final T seed, final UnaryOperator f)

生成

public static Stream generate(Supplier s)

————————————————

Date类

Instant 时间戳

用于“时间戳”的运算。它是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算

7.3Duration 和 Period

⚫ Duration:用于计算两个“时间”间隔

⚫ Period:用于计算两个“日期”间隔

7.4日期的操纵

⚫ TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。

⚫ TemporalAdjusters: 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现。

7.5解析与格式化

java.time.format.DateTimeFormatter类:该类提供了三种格式化方法:

⚫ 预定义的标准格式

⚫ 语言环境相关的格式

⚫ 自定义的格式

7.6时区的处理

⚫ Java8 中加入了对时区的支持,带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime

其中每个时区都对应着 ID,地区ID都为 “{区域}/{城市}”的格式

例如 :Asia/Shanghai 等

ZoneId:该类中包含了所有的时区信息

getAvailableZoneIds() : 可以获取所有时区时区信息

of(id) : 用指定的时区信息获取ZoneId 对象

————————————————

Java8新特性

Java之Java 8新特性 - 掘金 (juejin.cn)

——Map的新方法

Map 类型不支持 streams,不过Map提供了一些新的有用的方法来处理一些日常任务。Map接口本身没有可用的 stream()方法,但是你可以在键,值上创建专门的流或者通过 map.keySet().stream(),map.values().stream()和map.entrySet().stream()。

此外,Maps 支持各种新的和有用的方法来执行常见任务。

————————————————

  1. 异常体系

1) 异常层次

2) Throwable 类

3) 异常和错误

什么是异常

定义:在程序运行过程中出现的错误,称为异常。异常就是程序运行过程中出现了不正常现象导致程序的中断。

在Java中,把各种异常现象进行了抽象形成了异常类。

4.1.3 异常的捕获顺序

异常的捕获:一般按照由小到大的顺序,也就是先截获子异常再截获父异常

4.2 throws抛出处理

在定义方法时,如果方法体中有受检(编译时)异常需要预处理,可以捕获处理,也可以抛出处理。

处理异常时,使用throws抛出处理:

谁调用这个方法,谁负责处理该异常

在定义方法时,把异常抛出就是为了提醒方法的使用者,有异常需要预处理

在处理异常时,是选择捕获处理还是抛出处理

一般情况下,在调用其他方法时,如果被调用的方法有受检(编译时)异常需要预处理,选择捕获处理,因为你调用了方法, 你负责处理该异常。

在定义方法时,如果方法体中有受检异常需要预处理,可以选择捕获 ,也可以选择抛出处理。如果方法体中通过throw语句抛出了一个异常对象,所在的方法应该使用throws声明该异常。

————————————————

4.3 getMessage()和printStackTrace()

如何取得异常对象的具体信息,常用的方法主要有两种:

获取异常描述信息

使用异常对象的getMessage()方法,通常用于打印日志时

取得异常的堆栈信息

使用异常对象的printStackTrace()方法,比较适合于程序调试阶段

————————————————

4.4 方法覆盖中的异常处理

方法覆盖(重写)规则:

方法签名必须相同,方法名与参数列表就是方法签名

方法的返回值类型可以相同 ,子类方法的返回值类型也可以是父类方法返回值类型的子类型

子类方法的访问权限可以更宽泛(更大)

a、如果父类方法使用public修饰,子类方法只能是public修饰

b、如果父类方法使用protected修饰,子类方法可以是protected或者public修饰

子类方法的异常要比父类方法的异常更小

a、如果父类方法没有抛出异常,子类重写后也不能抛出异常

b、如果父类方法抛出了异常,子类方法可以抛出相同的异常,也可以抛出父类异常的子异常,也可以不抛出异常

————————————————

异常相关的面试题

5.1 谈谈你Java异常处理机制的理解?

Java对异常进行了分类,不同类型的异常分别用不同的Java类表示,所有异常的根类为 java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception。

Error: 表示应用程序本身无法克服和恢复的一种严重问题。

Exception: 表示程序还能够克服和恢复的问题,其中又分为系统异常和普通异常。

系统异常

系统异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者让软件死掉,例如,数组下标越界(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException)、类转换异常(ClassCastException)。

普通异常

普通异常是运行环境的变化或异常所导致的问题,是用户能够克服的问题,例如,网络断线,硬盘空间不够,发生这样的异常后,程序不应该死掉。

————————————————

Java为系统异常和普通异常提供了不同的解决方案,编译器强制普通异常必须try…catch处理或用throws声明继续抛给上层调用方法处理,所以普通异常也称为checked异常,而系统异常可以处理也可以不处理,所以编译器不强制用try…catch处理或用throws声明,所以系统异常也称为unchecked异常。

5.2 throw 和 throws 的区别?

throw

throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。

throw是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行throw一定是抛出了某种异常。

throw一般用于抛出自定义异常。

throws

throws语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理。

throws主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型。

throws表示出现异常的一种可能性,并不一定会发生这种异常。

————————————————

网络图片:https://uploadfiles.nowcoder.com/images/20180704/3807435_1530666258064_20577AE82E2EC5D6D44DD2CA01C99BBA

5.3 final、finally、finalize 的区别?

*

final

用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,被其修饰的类不可继承。

finally

异常处理语句结构的一部分,表示总是执行。

finalize

finalize 是Object 类的一个方法,所以Java对象都有这个方法,当某Java对象没有更多的引用指向的时候,会被垃圾回收器回收,该对象被回收之前,由垃圾回收器来负责调用此方法,通常在该方法中进行回收前的准备工作。该方法更像是一个对象生命周期的临终方法,当该方法被系统调用则代表该对象即将“死亡”,但是需要注意的是,我们主动行为上去调用该方法并不会导致该对象“死亡”,

————————————————

5.4 Java中异常分为哪些种类?

按照异常需要处理的时机,分为编译时异常(也叫受控异常)也叫 CheckedException 和运行时异常(也叫非受控异常)也叫 UnCheckedException。Java认为Checked异常都是可以被处理的异常,所以Java程序必须显式处理Checked异常。如果程序没有处理Checked 异常,该程序在编译时就会发生错误无法编译。这体现了Java 的设计哲学:没有完善错误处理的代码根本没有机会被执行。

对Checked异常处理方法有两种:

当前方法知道如何处理该异常,则用try…catch块来处理该异常。

当前方法不知道如何处理,则在定义该方法时声明抛出该异常。

对于运行时异常,只有当代码在运行时才发行的异常,编译的时候不需要try…catch。

比如:除数是0和数组下标越界等,其产生频繁,处理麻烦,若显示申明或者捕获将会对程序的可读性和运行效率影响很大。所以由系统自动检测并将它们交给缺省的异常处理程序。当然如果你有处理要求也可以显示捕获它们。

————————————————

5.5 error和exception的区别?

Error类和Exception类的父类都是Throwable类,他们的区别如下:

Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢出等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和预防,遇到这样的错误,建议让程序终止。

Exception类表示程序可以处理的异常,可以捕获且可能恢复。这种异常是由与程序设计的不完善而出现的问题,遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

Exception类又分为未检查异常(UnCheckedException)和受检查的异常(CheckedException)。

运行时异常ArithmeticException,IllegalArgumentException编译能通过,但是一运行就终止了,程序不会处理运行时异常,出现这类异常,程序会终止。

而受检查的异常,要么用 try…catch 捕获,要么用throws字句声明抛出,交给它的父类处理,否则编译不会通过。

————————————————

5.6 说出最常见的5个RuntimeException?

常见的异常有:

java.lang.NullPointerException 空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象

java.lang.ClassCastException 数据类型转换异常

java.lang.ClassNotFoundException 指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序试图通过字符串来加载某个类时可能引发异常

java.lang.NoSuchMethodException 方法不存在异常

java.lang.NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符

java.lang.IndexOutOfBoundsException 数组角标越界异常,常见于操作数组对象时发生

java.lang.IllegalArgumentException 方法传递参数错误

java.lang.NoClassDefFoundException 未找到类定义错误

SQLException SQL 异常,常见于操作数据库时的 SQL 语句错误

java.lang.InstantiationException 实例化异常

————————————————

6 总结

本文主要对Java中的异常相关的知识,进行了一下总结。

  • 异常的分类
  • 受控异常和非受控异常的区别
  • 异常的捕获和抛出处理
  • 异常的捕获顺序,先捕获小的,再捕获大的
  • 方法覆盖和异常的关系
  • 异常的5个关键字try、catch、finally、throws、throw

Java基础.docx

相关文章
|
1月前
|
安全 Java 编译器
Java基础-知识点(二)
Java基础-知识点(二)
13 0
|
1月前
|
存储 缓存 安全
Java基础-知识点(一)
Java基础-知识点(一)
17 0
|
6月前
|
存储 安全 Java
Java基础知识点总结2
Java基础知识点总结
65 0
|
6月前
|
设计模式 安全 Java
Java基础知识点总结1
Java基础知识点总结
45 0
|
6月前
|
存储 设计模式 算法
Java基础知识点总结3
Java基础知识点总结
60 0
|
6月前
|
存储 Java 数据库
java基础的知识点(一)
java基础的知识点(一)
|
存储 Java 容器
|
存储 Java
Java基础之复习(下)
Java基础之复习(下)
56 0
|
存储 Java C语言
Java基础之复习笔记(上)
Java基础之复习笔记(上)
60 0
|
Java 关系型数据库 Unix
Java基础知识面试题2
Java基础知识面试题2
201 0
下一篇
无影云桌面