目录
  1. 1. JAVA基础
    1. 1.1. java的第一个程序
      1. 1.1.1. java的输入与输出
      2. 1.1.2. java的各种类型的数据
        1. 1.1.2.1. 整数类型
        2. 1.1.2.2. 浮点数:
        3. 1.1.2.3. 布尔类型
        4. 1.1.2.4. 字符型
        5. 1.1.2.5. 类型转换的规则
  2. 2. 面向对象编程
    1. 2.1. 概念
    2. 2.2. 继承
      1. 2.2.1. 方法的重写(override)
    3. 2.3. 多态
    4. 2.4. 抽象类
    5. 2.5. interface
    6. 2.6. 封装
      1. 2.6.1. 概念
      2. 2.6.2. 权限修饰符
      3. 2.6.3. 构造器(构造方法)
      4. 2.6.4. 关键字—this
      5. 2.6.5. JavaBean
      6. 2.6.6. UML类
      7. 2.6.7. 关键字—package
      8. 2.6.8. 关键字—import
      9. 2.6.9. JDK中主要的包介绍
    7. 2.7. Object类
      1. 2.7.1. equals方法
      2. 2.7.2. toString()方法
    8. 2.8. 包装类(Wrapper)
      1. 2.8.1. 装箱
      2. 2.8.2. 拆箱
      3. 2.8.3. 字符串与基本数据类型转换
  3. 3. 异常处理
    1. 3.1. 概述
    2. 3.2. 常见异常
    3. 3.3. 异常举例
    4. 3.4. 异常处理
    5. 3.5. 异常处理举例
    6. 3.6. 声明抛出异常
    7. 3.7. 自定义异常类
    8. 3.8. 反射
      1. 3.8.1. 获取class类对象的方式
    9. 3.9. Class对象的功能
    10. 3.10. 注解
      1. 3.10.1. JDK 中预置的一些注解
      2. 3.10.2. 自定义注解
      3. 3.10.3. 元注解
      4. 3.10.4. 解析、使用注解
    11. 3.11. JVM核心
      1. 3.11.1. 加载
      2. 3.11.2. 链接
      3. 3.11.3. 初始化
      4. 3.11.4. 类的引用
      5. 3.11.5. 类加载器
JAVA

JAVA基础

java的第一个程序

  • JDK 、JRE、JVM 的区别

    JDK包含了JRE,JRE包含了JVM。JVM(java virtual machine) JRE(java runtime environment) JDK(java development kit)

  • package 类似于文件夹,用于管理各种class。包名的命名是域名倒着写,类似于com.baidu。

  • API(application programming interface)应用程序接口。API的作用类似于字典。在API中查找各种包中包含的类的使用说明

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.guigu.java;
import java.lang.String;
/**API文档使用,用来注释各个类的作用,用途
* @author xinyu
* helloword 类的作用:
* 使用的形参:....
*
*/
public class Helloworld{}
public static void main(String[]args){
System.out.println("hello,world");
}
}

主函数main在public class 函数里面。一个package里面只能有一个public 类。主函数是一个程序的入口。

java的输入与输出

  • 输出
1
2
3
System.out.println(" ");//输出换行
System.out.print(" ")//输出不换行
System.out.printf("%d",a);//c语言类型的输出
  • 输入
1
2
3
import java.util.Scanner;
Scanner s=new Scanner(System.in);//创建一个Scanner类的对象s
int a=s.nextInt();

java的各种类型的数据

image-java数据类型 image-各种进制的表示

整数类型

==Integer.toBinaryString(a)==把a转为二进制表示形式

==Integer.toOctalString(a)==把a转为8进制形式

==Integer.toHexString(a)==把a转为16进制

  • byte

占用一个字节(8位)表示范围 -128——127。

  • short

占用2个字节(16位)大约正负3*10^4^多。

  • int

占用4个字节, (2^31)-1。大约正负21亿。

  • long

占用8个字节。 2^63^-1

浮点数:

  • 浮点数默认为double类型,要将其变为float类型,需要在数字后面加F/f

  • 科学计数法 列如3.12e2 表示3.12*10^2^。

布尔类型

  • 1代表真,0 代表假

字符型

  • char a=’sf’,注意使用的是单引号,String类型才使用双引号

  • 字符可以直接转化为数字,是使用ASC Ⅱ 转化的

  • 可以使用强制转型把数字转化为字符型(char)a;

类型转换的规则

  • 容量小的数据类型可以自动转换为容量大的数据类型
image-自动转换
1
2
3
4
int i=3;//编译不会报错
double b=i;
float t=2.3f;
double c=t;
  • 可以将整型变量直接赋值给byte,short,char 只要不超出其范围
1
2
3
char a=2
short b=1234
char c=4
  • 强制转换

强制转换是让不能自动转换的数字强制转换为我们想要的类型。使用方法:

1
2
double a=2.3;//把a强制转换为float类型。
float b=(float)a;

面向对象编程

概念

==类==是面向对象编程语言的一个重要概念,它是对一项事物的抽象概括,可以包含该事物的一些属性定义,以及操作属性的方法。
==实例==就是创建这个类对应的实际对象。类只是对事物的描述,而实例化就是相当于为这个描述开辟了一块内存。
==变量(属性)==分为:
成员变量:
1、成员变量定义在类中,在整个类中都可以被访问。

​ 2、成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。

​ 3、成员变量有默认初始化值。
类变量(静态变量):
​ 由static关键字修饰的变量称为静态变量,其实质上就是一个全局变量。如果某个内容是被所有对象所共享,那么该内容就应该用静态修饰

成员变量和类变量的区别:
1、两个变量的生命周期不同

  • 成员变量随着对象的创建而存在,随着对象的回收而释放。

  • 静态变量随着类的加载而存在,随着类的消失而消失。

    2、调用方式不同

  • 成员变量只能被对象调用。

  • 静态变量可以被对象调用,还可以被类名调用。

    3、别名不同

  • 成员变量也称为实例变量。

  • 静态变量也称为类变量。

    4、数据存储位置不同

  • 成员变量存储在==堆内存==的对象中,所以也叫对象的特有数据。

  • 静态变量数据存储在方法区(共享数据区)的==静态区==,所以也叫对象的共享数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//一个简单的例子
public class People{
//成员变量
double height;
int age;
//构造函数 用于这个class创建的时候给成员变量赋值。如果不写,编译器会自动加上一个空构造函数
public People(int age,double height){
this.age = age;
this.height = height;
}
//成员方法
void eating(){System.out.println("yummy")}
public static void main(String[] args){
People p1 = new People()
}
}

继承

面向对象的三个基本特征之一(另外两个是多态和封装)。
==继承==就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
子类的创建可以增加新数据、新功能,可以继承父类全部的功能,但是不能选择性的继承父类的部分功能。继承是==类与类之间==的关系,不是对象与对象之间的关系。
作用:

  • 继承的出现提高了代码的复用性
  • 继承的出现让类与类之间产生了关系,提供了多态的前提
  • 不要仅为了获取其他类中某个功能而去继承

关于继承的规则:

  • 子类不能直接访问父类中私有的(private)的成员变量和方法。

img

方法的重写(override)

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

要求

  • 重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型。
  • 重写方法不能使用比被重写方法更严格的访问权限
  • 重写和被重写的方法须同时为static的,或同时为非static的
  • 子类方法抛出的异常不能大于父类被重写方法的异常

img

img

###继承实现

java 中,使用关键字==extends==来体现子类继承父类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Animal {
void run(){
System.out.println("run,run");
}//权限这里,方法如果是protected,则不能被重写,只能被使用
protected void eat(){
System.out.println("yummy");
}
public static void main(String[]args){
Scanner s1=new Scanner(System.in);
egg e1=new egg();
bird b1=new bird();
Animal a1=new Animal();
System.out.print("which animal is your favorite ");
String kind=s1.nextLine();
switch (kind){
case "egg":e1.creep();break;
case"bird":b1.run();b1.flying();break;
case "animal":a1.eat();a1.run();break;
}
}
}
class bird extends Animal {
void run(){

//这里虽然方法名和父类的一样,但是可以写不一样的内容,叫做重写(override)
System.out.println("i am a little bird");
}
//这里是子类特有的方法。父类是没有的
void flying(){
System.out.println("swing");
}
}
class egg extends Animal{
void creep(){
super.run();//这里的sueper 代表了egg的父类Animal
System.out.println("creep slowly");
}
}

多态

多态是建立在重写(override)和继承(extends)上的
三个必要条件:要有继承,要有方法重写,父类引用指向子类引用
主要的使用是在父类之下还有多个子类,然后,在其他的函数定义,需要使用这个类以及它的子类的时候,我们可以模糊化。用父类去代表整个子类。在使用这个函数的时候,再明确指出使用哪一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class ani_mal {
void voice(){
System.out.println("普通动物叫声");
}
public static void main(String[]args){
text_1 t1=new text_1();
text_1 t2=new text_1();
ani_mal c1=new Cat();//这里就是用ani_mal 这个父类来建立一个Cat对象
ani_mal d1=new Dog();
t1.TextAnimal(c1);
t2.TextAnimal(d1);
//d1.watchdoor();但是,如果用父类来创建的一个子类的对象,那么,子类特有的函数(方法)是无法调用的
//c1.catchmouse();我们可以使用强制转型来使用子类特有的函数
Cat c2=(Cat)c1;
Dog d2=(Dog)d1;
c2.catchmouse();
d2.watchdoor();
}
}
class Cat extends ani_mal{
// override
void voice(){
System.out.println("喵喵喵");
}
void catchmouse(){
System.out.println("抓老鼠");
}
}
class Dog extends ani_mal {
void voice() {
System.out.println("汪汪汪");
}
void watchdoor(){
System.out.println("汪~~");
}
}
class text_1{//这个类里的函数,用了ani_mal 这个类去代表了父类以及他的延伸的两个子类
void TextAnimal(ani_mal a1){
a1.voice();
}
}

抽象类

在父类里面定义一个抽象方法,在不同的子类里面分别重写这个方法。关键字是abstract-

  • abstract class 抽象类
  • abstract void run() 抽象方法

有抽象方法的类只能定义为抽象类。抽象类里也可以有普通的方法。

  • 抽象类不能实体化,即抽象类没有对象
  • 抽象类只能用来继承
  • 抽象方法必须被子类实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public abstract class An_imal {
abstract void run();//这个抽象的方法,An_imal的子类都必须把这个方法重写(具体化),而且这个抽象类是不能创建对象的
void eat() {
System.out.print("after eating food");
run();//这里是多态的应用.不同的子类,调用自身的run方法
}

public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print("which is your favorite animal,cat or dog ");
String a = s.nextLine();
switch (a) {
case "cat":{An_imal c1 = new Ct();c1.eat();}break;
case "dog":{An_imal d1=new Dg();d1.eat();}break;
default:System.out.println("error!!");
}
}
}
class Ct extends An_imal{
//抽象方法的实现
void run(){
System.out.println(" it is happily running");
}
}
class Dg extends An_imal{
void run(){
System.out.println(" it is going to sleep");
}
}

interface

接口:接口只定义各种方法,之后的继承它的类必须要把那些方法实现。类似于继承,它使用的关键字是implements

  • 有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
  • 接口(interface)是抽象方法常量值的定义的集合。
  • 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
  • 实现接口类:class SubClass implements InterfaceA{ }一个类可以实现多个接口接口也可以继承其它接口。

img

1
2
3
4
5
6
7
public interface Interface {
//接口中只能有常量和抽象的方法
String name="木木";
void crying();
void stupid();
void lonely();
}

封装

概念

面向对象特征之一:封装和隐藏 :使用者对类内部定义的属性(对象的成员变量)的直接操作会导致数据的错误、混乱或安全性问题。

1
2
3
4
5
6
7
8
9
10
class Animal {
public int legs;
}
public class Zoo{
public static void main(String args[]){
Animal xb=new Animal();
xb.legs = -1000;//错误的赋值
System.out.println(xb.legs);
}
}
  • 应该将legs属性保护起来,防止乱用。保护的方式:信息隐藏

    Java中通过将数据声明为私有的(private),再提供公共的(public)方法:getXxx()和setXxx()实现对该属性的操作,以实现下述目的:

  • 隐藏一个类中不需要对外提供的实现细节;

  • 使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作;

  • 便于修改,增强代码的可维护性;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Animal{
private int legs;//将属性legs定义为private,只能被Animal类内部访问
public void setLegs(int i){
if (i != 0 && i != 2 && i != 4){
System.out.println("Wrong number of legs!");
return;
}
legs=i;
}
public int getLegs(){
return legs;
}
}
public class Zoo{
public static void main(String args[]){
Animal xb=new Animal();
xb.setLegs(4); //xb.setLegs(-1000);
System.out.println(xb.getLegs());
}
}

权限修饰符

Java权限修饰符public、protected、private置于类的成员定义前,用来限定对象对该类成员的访问权限。

修饰符 类内部 同一个包 子类 任何地方
private Yes
(缺省) Yes Yes
protected Yes Yes Yes
public Yes Yes Yes Yes
  • 对于class的权限修饰只可以用public和default(缺省)。
  • public类可以在任意地方被访问。
  • default类只可以被同一个包内部的类访问。

构造器(构造方法)

  • 构造器的特征它具有与类相同的名称
  • 它不声明返回值类型。(与声明为void不同)
  • 不能被static、final、synchronized、abstract、native修饰
  • 不能有return语句返回值

构造器的作用:创建对象;给对象进行初始化

  • 如:Order o = new Order(); Person p = new Person(Peter,15);
  • 如同我们规定每个“人”一出生就必须先洗澡,我们就可以在“人”的构造方法中加入完成“洗澡”的程序代码,于是每个“人”一出生就会自动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们要“洗澡”了。

语法格式

img

1
2
3
4
5
6
7
8
public class Animal {
private int legs;
public Animal() {legs = 4; } //构造器
public void setLegs(int i) { legs = i; }
public int getLegs(){return legs;}
}
//创建Animal类的实例:Animal a=new Animal();
//调用构造器,将legs初始化为4。

根据参数不同,构造器可以分为如下两类:

  • 隐式无参构造器(系统默认提供)
  • 显式定义一个或多个构造器(无参、有参)

注意:

  • Java语言中,每个类都至少有一个构造器
  • 默认构造器的修饰符与所属类的修饰符一致
  • 一旦显式定义了构造器,则系统不再提供默认构造器
  • 一个类可以创建多个重载的构造器
  • 父类的构造器不可被子类继承

构造器重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Person {
private String name;
private int age;
private Date birthDate;
public Person(String name, int age, Date d) {
this.name = name;
this.age = age;
this.birthDate = d;
}
public Person(String name, int age) {
this(name, age, null);
//this.name=name; this.age=age; this.birthDate=null;
}
public Person(String name, Date d) {
this(name, 30, d);
//this.name=name; this.age=30; this.birthDate=d;
}
public Person(String name) {
this(name, 30); //this.name=name; this.age=30;
}
}

关键字—this

在java中,this关键字比较难理解,它的作用和其词义很接近。

  • 它在方法内部使用,即这个方法所属对象的引用;
  • 它在构造器内部使用,表示该构造器正在初始化的对象。

this表示当前对象,可以调用类的属性、方法和构造器

什么时候使用this关键字呢?

  • 当在方法内需要用到调用该方法的对象时,就用this。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Person{		// 定义Person类
private String name ;
private int age ;
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void getInfo(){
System.out.println("姓名:" + name);
this.speak();//此处this可写可不写
}
public void speak(){
System.out.println(“年龄:” + this.age);
}
}
  • 形参与成员变量重名时,如果在方法内部需要使用成员变量,必须添加this来表明该变量时类成员
  • 任意方法内,如果使用当前类的成员变量或成员方法可以在其前面添加this,增强程序的阅读性

使用this调用本类的构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Person{		// 定义Person类
private String name;
private int age;
public Person(){ // 无参构造
System.out.println("新对象实例化");
}
public Person(String name){
this(); // 调用本类中的无参构造方法
this.name = name ;
}
public Person(String name,int age){
this(name) ; // 调用有一个参数的构造方法
this.age = age;
}
public String getInfo(){
return "姓名:" + name + ",年龄:" + age ;
}
}
  • 使用this()必须放在构造器的首行!
  • 使用this调用本类中其他的构造器,保证至少有一个构造器是不用this的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person{  // 定义Person类
String name;
Person(String name){
this.name = name;
}
public void getInfo(){
System.out.println("Person类 --> " + this.name) ;
}
public boolean compare(Person p){
return this.name==p.name;
}
}
public class TestPerson{
public static void main(String args[]){
Person per1 = new Person("张三") ;
Person per2 = new Person("李四") ;
per1.getInfo() ; // 当前调用getInfo()方法的对象是per1
per2.getInfo() ; // 当前调用getInfo()方法的对象是per2
boolean b = per1.compare(per2);
}
}

JavaBean

  • JavaBean是一种Java语言写成的可重用组件。
  • 所谓javaBean,是指符合如下标准的Java类:
    • 类是公共的
    • 有一个无参的公共的构造器有属性
    • 有对应的get、set方法
  • 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TestJavaBean{
private String name; //属性一般定义为private
private int age;
public TestJavaBean(){}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}

UML类

img

  • +表示 public 类型, - 表示 private 类型,#表示protected类型
  • 方法的写法: 方法的类型(+、-) 方法名(参数名: 参数类型):返回值类型

关键字—package

package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包。(若缺省该语句,则指定为无名包)。它的格式为: package 顶层包名.子包名 ;

1
2
3
4
5
6
7
//举例:pack\Test.java
package p1; //指定类Test属于包p1
public class Test{
public void display(){
System.out.println("in method display()");
}
}
  • 包对应于文件系统的目录,package语句中,用 “.” 来指明包(目录)的层次;
  • 包通常用小写单词,类名首字母通常大写。

关键字—import

为使用定义在不同包中的Java类,需用import语句来引入指定包层次下所需要的类或全部类(.*)。

import语句告诉编译器到哪里去寻找类。

语法格式:import 包名[.子包名…]. <类名 |*>

1
2
3
4
5
6
7
import  p1.Test;   //import p1.*;表示引入p1包中的所有类
public class TestPackage{
public static void main(String args[]){
Test t = new Test(); //Test类在p1包中定义
t.display();
}
}
  • 若引入的包为:java.lang,则编译器默认可获取此包下的类,不需要再显示声明。
  • import语句出现在package语句之后、类定义之前
  • 一个源文件中可包含多个import语句
  • 可以使用import lee.* ;语句,表明导入lee包下的所有类。而lee包下sub子包内的类则不会被导入。import lee.sub.*;
  • import语句不是必需的,可坚持在类里使用其它类的全名
  • JDK 1.5加入import static语句

JDK中主要的包介绍

  • java.lang—-包含一些Java语言的核心类,如String、Math、Integer、 System和Thread,提供常用功能
  • java.net—-包含执行与网络相关的操作的类和接口。
  • java.io —-包含能提供多种输入/输出功能的类。
  • java.util—-包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
  • java.text—-包含了一些java格式化相关的类
  • java.sql—-包含了java进行JDBC数据库编程的相关类/接口
  • java.awt—-包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。
  • java.applet—-包含applet运行所需的一些类。

Object类

  • Object类是所有Java类的根父类
  • 如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类
1
2
3
method(Object obj){…}//可以接收任何类作为其参数
Person o=new Person();
method(o);

Object类中的主要方法

方法名称 类型 描述
public Object() 构造 构造方法
public boolean equals(Object obj) 普通 对象比较
public int hashCode() 普通 取得Hash码
public String toString() 普通 对象打印时调用

equals方法

==操作符:

  • 基本类型比较值:只要两个变量的值相等,即为true. int a=5; if(a==6){…}

    引用类型比较引用(是否指向同一个对象):只有指向同一个对象时,==才返回true.

    Person p1=new Person(); Person p2=new Person(); if (p1==p2){…}

  • “==”进行比较时,符号两边的数据类型必须兼容(可自动转换的基本数据类型除外),否则编译出错;

equals()

  • 所有类都继承了Object,也就获得了equals()方法。还可以重写。

  • 只能比较引用类型,其作用与“==”相同,比较是否指向同一个对象。格式:obj1.equals(obj2)

  • 特例

    :当用equals()方法进行比较时,对类File、String、Date及包装类(Wrapper Class)来说,是

    比较类型及内容

    而不考虑引用的是否是同一个对象;

    • 原因:在这些类中重写了Object类的equals()方法。

可重写equals方法更改两个引用数据类型相等的条件

toString()方法

  • toString()方法Object类中定义,其返回值是String类型,返回类名和它的引用地址。在
  • 进行String与其它类型数据的连接操作时,自动调用toString()方法Date now=new Date(); System.out.println(“now=”+now); 相当于 System.out.println(“now=”+now.toString());
    可以根据需要在用户自定义类型中重写toString()方法
    如String类重写了toString()方法,返回字符串的值。s1=“hello”; System.out.println(s1);//相当于System.out.println(s1.toString());
  • 基本类型数据转换为String类型时,调用了对应包装类的toString()方法int a=10; System.out.println(“a=”+a);

包装类(Wrapper)

  • 针对八种基本定义相应的引用类型—包装类(封装类)
  • 有了类的特点,就可以调用类中的方法。
基本数据类型 包装类
boolean Boolean
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double

装箱

基本数据类型包装成包装类的实例

  • 通过包装类的构造器实现:
    • int i = 500;
    • Integer t = new Integer(i);
  • 还可以通过字符串参数构造包装类对象:
    • Float f = new Float(“4.56”);
    • Long l = new Long(“asdf”);
    • //NumberFormatException

拆箱

获得包装类对象中包装的基本类型变量

  • 调用包装类的.xxxValue()方法:
    • boolean b = bObj.booleanValue();
  • JDK1.5之后,支持自动装箱,自动拆箱。但类型必须匹配。

字符串与基本数据类型转换

字符串转换成基本数据类型

  • 通过包装类的构造器实现:
    • int i = new Integer(“12”);
  • 通过包装类的parseXxx(String s)静态方法:
    • Float f = Float.parseFloat(“12.1”);

基本数据类型转换成字符串

  • 调用字符串重载的valueOf()方法:
    • String fstr = String.valueOf(2.34f);
  • 更直接的方式:
    • String intStr = 5 + “”

包装类在实际开发中用的最多的在于字符串变为基本数据类型。

异常处理

概述

在使用计算机语言进行项目开发的过程中,即使程序员把代码写得尽善尽美,在系统的运行过程中仍然会遇到一些问题,因为很多问题不是靠代码能够避免的,比如:客户输入数据的格式,读取文件是否存在,网络是否始终保持通畅等等。

异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)

Java程序在执行过程中所发生的异常事件可分为两类:

  • Error

    : Java虚拟机无法解决的严重问题。

    • 如:JVM系统内部错误、资源耗尽等严重情况。
  • 一般不编写针对性的代码进行处理。

  • Exception

    : 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:

    • 空指针访问
    • 试图读取不存在的文件
    • 网络连接中断

解决方法

  • 一是遇到错误就终止程序的运行
  • 另一种方法是由程序员在编写程序时,就考虑到错误的检测、错误消息的提示,以及错误的处理。

捕获错误最理想的是在编译期间,但有的错误只有在运行时才会发生。比如:除数为0,数组下标越界等

分类

编译时异常

  • 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。
  • java.lang.RuntimeException类及它的子类都是运行时异常。
  • 对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响

运行时异常

  • 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一般性异常。编译器要求java程序必须捕获或声明所有编译时异常。
  • 对于这类异常,如果程序不处理,可能会带来意想不到的结果。

Java异常类层次

img

常见异常

  • java.lang.RuntimeException
    • ClassCastException
    • ArrayIndexOutOfBoundsException
    • NullPointerException
    • ArithmeticException
  • java.io.IOExeption
    • FileNotFoundException
    • EOFException
  • java.lang.ClassNotFoundException
  • java.lang.InterruptedException
  • java.io.FileNotFoundException
  • java.sql.SQLException

异常举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Test6_1{
public static void main(String[] args) {
String friends[]={"lisa","bily","kessy"};
for(int i=0;i<5;i++) {
System.out.println(friends[i]); //friends[4]?
}
System.out.println("\nthis is the end");//未输出
}
}
/*
程序Test6_1编译正确,运行结果:java Test6_1
lisa
bily
kessy
java.lang.ArrayIndexOutOfBoundsException at Test6_1.main(Test6_1.java:5)
Exception in thread "main"
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
public class NullRef{
int i=1;
public static void main(String[] args) {
NullRef t=new NullRef();
t=null;
System.out.println(t.i);
}
}
/*
程序NullRef.java编译正确,运行结果:java NullRef
java.lang.NullPointerException at NullRef.main(NullRef.java:6)
Exception in thread "main"
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DivideZero{
int x;
public static void main(String[] args) {
int y;
DivideZero c=new DivideZero();
y=3/c.x;
System.out.println(“program ends ok!”);
}
}
/*
程序DivideZero.java编译正确,运行结果:java DivideZero
java.lang.ArithmeticException: / by zero
at DivideZero.main(DivideZero.java:6)
Exception in thread "main"
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person {
public static void main(String[] args) {
Object obj = new Date();
Person person;
person = (Person)obj;
System.out.println(person);
}
}
/*
程序Person.java编译正确,运行结果:java Person
java.lang. java.lang.ClassCastException
at Person.main(Person.java:5)
Exception in thread "main"
*/

异常处理

在编写程序时,经常要在可能出现错误的地方加上检测的代码,如进行x/y运算时,要检测分母为0,数据为空,输入的不是数据而是字符等。过多的分支会导致程序的代码加长,可读性差。因此采用异常机制。

Java异常处理采用异常处理机制,将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序简洁,并易于维护。

  • Java提供的是异常处理的抓抛模型
  • Java程序的执行过程中如出现异常,会生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常
  • 异常对象的生成
    • 虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出
    • 由开发人员手动创建:Exception exception = new ClassCastException();——创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样
  • 如果一个方法内抛出异常,该异常对象会被抛给调用者方法中处理。如果异常没有在调用者方法中处理,它继续被抛给这个调用方法的上层方法。这个过程将一直继续下去,直到异常被处理。这一过程称为捕获(catch)异常。
  • 如果一个异常回到main()方法,并且main()也不处理,则程序运行终止。程序员通常只能处理Exception,而对Error无能为力。

异常处理是通过try-catch-finally语句实现的

1
2
3
4
5
6
7
8
9
10
11
12
13
try{
//......
//可能产生异常的代码
}catch( ExceptionName1 e ){
//......
//当产生ExceptionName1型异常时的处置措施
}catch( ExceptionName2 e ){
//......
//当产生ExceptionName2型异常时的处置措施
}finally{//可写可不写
//......
//无论是否发生异常,都无条件执行的语句
}

try

捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的代码放在try语句块中。

catch (Exceptiontype e)

在catch语句块中是对异常对象进行处理的代码。每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。

如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。

比如:可以用ArithmeticException类作为参数的地方,就可以用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。但不能是与ArithmeticException类无关的异常,如NullPointerException(catch中的语句将不会执行)。

捕获异常的有关信息:

与其它对象一样,可以访问一个异常对象的成员变量或调用它的方法。

  • getMessage() 获取异常信息,返回字符串
  • printStackTrace() 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。

finally

  • 捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。
  • 不论在try代码块中是否发生了异常事件,catch语句是否执行,catch语句是否有异常,catch语句中是否有return,finally块中的语句都会被执行。
  • finally语句和catch语句是任选的

img

异常处理举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Test6_2{
public static void main(String[] args){
String friends[]={"lisa","bily","kessy"};
try {
for(int i=0;i<5;i++) {
System.out.println(friends[i]);
}
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("index err");
}
System.out.println("\nthis is the end");
}
}
/*
程序Test6_2运行结果:java java6_2
lisa
bily
kessy
index err
this is the end
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class DivideZero1{
int x;
public static void main(String[] args) {
int y;
DivideZero1 c=new DivideZero1();
try{
y=3/c.x;
}catch(ArithmeticException e){
System.out.println("divide by zero error!");
}
System.out.println("program ends ok!");
}
}
/*
程序DivideZero1运行结果:java DivideZero1
divide by zero error!
program ends ok!
*/

声明抛出异常

声明抛出异常是Java中处理异常的第二种方式

  • 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
  • 在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
  • 重写方法不能抛出比被重写方法范围更大的异常类型。在多态的情况下,对methodA()方法的调用-异常的捕获按父类声明的异常处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A {
public void methodA() throws IOException {
//……
}
}
class B1 extends A {
public void methodA() throws FileNotFoundException {
// ……
}
}
class B2 extends A {
public void methodA() throws Exception { //报错
// ……
}
}

人工抛出异常

Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要人工创建并抛出。

  • 首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运行环境)。IOException e = new IOException();throw e;
  • 可以抛出的异常必须是Throwable或其子类的实例。下面的语句在编译时将会产生语法错误: throw new String("want to throw");

自定义异常类

  • 一般地,用户自定义异常类都是RuntimeException的子类。
  • 自定义异常类通常需要编写几个重载的构造器。
  • 自定义的异常类对象通过throw抛出。
  • 自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。
  • 用户自己的异常类必须继承现有的异常类

创建

1
2
3
4
5
6
7
8
9
10
11
class MyException extends Exception {
static final long serialVersionUID = 1L;
private int idnumber;
public MyException(String message, int id) {
super(message);
this.idnumber = id;
}
public int getId() {
return idnumber;
}
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Test6_5{
public void regist(int num) throws MyException {
if (num < 0)
throw new MyException("人数为负值,不合理", 3);
else
System.out.println("登记人数" + num );
}
public void manager() {
try {
regist(100);
} catch (MyException e) {
System.out.print("登记失败,出错种类"+e.getId());
}
System.out.print("本次登记操作结束");
}
public static void main(String args[]){
Test6_5 t = new Test6_5();
t.manager();
}
}

img

反射

反射:被视为动态语言的关键。它允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

好处

  • 可以在程序的运行过程中操作这些对象。
  • 可以解耦,提高程序的可拓展性

获取class类对象的方式

1、Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象
多用于配置文件,将类名定义在配置文件中,读取文件,加载类

2、类名.Class:通过类名的属性Class获取
多用于参数的传递

3、对象.getclass():getclass()方法在Object类中定义。

这三种方法分别对应了Java代码在计算机中经历的三个阶段。

类加载器把java代码加载为了Class类对象时,成员变量、构造方法、成员方法都被抽取出来,封装为对象了。所有的成员变量对象都放在了一个叫做Filed[] 的数组里。其他同理。

不管通过那种方式,获取到的Class对象是同一个。
因为同一个字节码文件(*.class)在程序运行的过程中,只会被加载一次。

Class对象的功能

  • 获取功能
    1、获取成员变量们

    • Filed[] getFileds() 获取所有public修饰的成员变量

      1
      2
      3
      4
      5
      6
      Class PersonClass = Person.class;
      Filed[] getFileds() 获取所有public修饰的成员变量
      Field[] fields= PersonClass.getFields();
      for (Field field:fields){
      System.out.println(field);
      }
 - Filed getFiled(String name) 获取某个成员变量

    
1
2
3
4
5
6
7
8
9
10
11
12
13
/        得到成员变量之后有啥用:可以获取成员变量的值和设置成员变量的值
// get() & set()
Field a = PersonClass.getField("a");
Person p1 =new Person();


// 获取值
Object value = a.get(p1);
System.out.println(value);

// 设置值
a.set(p1,15);
System.out.println(p1.a);
- Filed[] getDeclaredFields() 获取所有的成员变量。意味着私有的成员变量也能获取。
1
2
3
4
//        declared 方法
Field[] fields = PersonClass.getDeclaredFields();
for (Field field:fields){
System.out.println(field);
- Filed getDeclaredField(String name)
1
2
3
4
5
6
//       获取单个的declared对象
Field nameField = PersonClass.getDeclaredField("name");
// 这里,使用私有的成员变量时需要忽略访问权限修饰符额安全检查
nameField.setAccessible(true);
nameField.set(p1,"小黄");
System.out.println ((String)nameField.get(p1));
2、获取构造方法们 作用:获取到构造方法后,可以创建对应的对象。 - Constructor<?>[] getConstructors() - Constuctor<T> getConstructor(类<?>... parameterTypes)
1
2
3
Class classPerson = Person.class;
Constructor constructor = classPerson.getConstructor(String.class,int.class,int.class,String.class);
Person person =(Person) constructor.newInstance("aaa",123,122,"小小");
- Constructor<T> getDeclaredConstructor(类<?>... ParameterTypes) - Constructor<?>[] getDeclaredConstructors() 3、获取成员方法们 - Method[] getMethods() - Method getMethod(String name ,类<?>... paraterTpyes)
1
2
3
4
5
Class personClass = Person.class;
Method method = personClass.getMethod("setB", String.class);
Person p1= new Person();
method.invoke(p1,"起飞");
System.out.println(p1.getB());
- Method[] getDeclareMethods() - Method getDeclareMethod(String name ,类<?>... paraterTpyes) 4、获取类名 - String getName()

注解

概念:说明程序的,是给计算机看的。

作用分类:

  • 编写文档:通过代码里标识的注解生成doc文档
  • 代码分析;通过代码标识的注解对代码进行分析(使用反射)
  • 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查

JDK 中预置的一些注解

1、@override 检测被该注解标注的方式是否是继承自父类(接口)

2、@Deprecated 该注解标注的内容,已经过时

3、@SuppressWarnings 压制警告。一般传入参数”all”

自定义注解

格式:public @interface 注解名称{}

本质:注解本质上是一个接口,该接口默认继承Annotation接口。

属性:接口中可以定义的成员方法。
要求:

  • 属性的返回值类型
    1、基本数据类型
    2、String
    3、枚举
    4、注解
    5、以上类型的数组

  • 定义了属性,在使用时需要给属性赋值

元注解

用于描述注解的注解
1、@Target 描述注解能够作用的位置
2、@Retention 描述注解被保留的阶段
3、@Documented 描述注解是否被抽取到api文档中
4、@Inherited 描述注解是否被子类继承

解析、使用注解

  • 1、获取有注解类的字节码文件对象
    Clss xxx = xxx.class
  • 2、获取字节码文件对象里的注解对象
    XX name = xxx.getAnnotation(XX.class).//在内存中生成了 一个该注解接口的子类实现对象。
  • 3、调用注解对象中定义的抽象方法,获取返回值
    Strng、int... xxxx = name.方法()

JVM核心

类加载机制:JVM把class文件加载到内存,并对数据进行校验、解析和初始化,最终形成JVM可以直接使用的Java类型的过程

加载

将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时二进制的数据结构。在堆中生成一个代表整个类的java.lang.Class对象,作为方法区类数据的访问入口。这个类就是反射中我们得到的那个Class类

链接

将Java类的二进制代码合并到JVM的运行状态之中的过程。

  • 验证;确保加载的类的信息符合JVM规范,没有安全方面的问题
  • 准备:正式为类变量即static变量分配内存并设置类变量初始值的阶段。这些内存都将在方法区进行分配
  • 解析:虚拟机常量池内的符号引用替换为直接引用的过程

初始化

初始化阶段是执行类构造器()方法的过程。类构造器方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的。

当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化

虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步

当访问一个Java类的静态域时,只有真正声明这个域的类才会被初始化。

方法区获取到每个class 的运行时数据,同时也进行静态变量和方法的初始化。之后才产生一个与之对应的在堆中的代表这整个类的java.lang.Class对象。之后才执行代码。main方法执行时,会在栈中生成一个栈帧(每个方法执行时,都会生成一个自己的栈帧)。

类的引用

什么时候会发生类的初始化:

  • new一个类的对象
  • 使用类的静态成员
  • 使用java.lang.reflect包的方法对类进行反射调用
  • 当初始化一个类,如果父类没有初始化,则会先初始化它的父类

类的被动引用(不会发生类的初始化)

  • 引用final的常量时,不会发生初始化
  • 访问静态域时,只有真正声明这个域的类才会初始化。例如:B extends A,A中声明了一个static int width。在main方法中,使用B.width,但是初始化的类是A

类加载器

类加载器的层次结构

  • 引导类加载器:它用来加载Java 的核心库(JAVA_HOME/jre/lib/rt.jar),是用原生代码(c++)来实现的,并不继承自java.lang.Classloader

以下的类都继承自java.lang.ClassLoader

  • 扩展类加载器:用来加载(JAVA_HOME/jre/ext/*.jar)
  • 应用程序类加载器(application class loader)
  • 自定义类加载器(User Defined ClassLoader)

java.lang.ClassLoader类的基本职责:根据一个指定的类的名称,找到或者生成对应的字节码文件,然后从这些字节码代码中定义出一个java类,即java.lang.Class类的实例。除此之外,ClassLoader还负责加载java应用所需要的资源,如图像,文件和配置文件等

文章作者: Dr-xinyu
文章链接: https://dr-xinyu.github.io/2019/11/08/JAVA/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 心雨
打赏
  • 微信
  • 支付寶