一篇随笔入门Java
Java
helloWorld
- 随便新建一个文件夹存放代码
- 新建一个java文件
- 文件后缀名.java
- Hello.java
- 【注意】系统可能不显示后缀名要手动打开
- 代码
public class Hello{
public static void main(String[] args){
System.out.print("Hello,World!") ;
}
}
- 编译 javac java文件,会生成一个class文件
java Hello.java
- 运行class文件,java class文件
java Hello
程序运行机制
- 编译型
- 操作系统 C、C++
- 解释型
- 网页、服务器脚本,对速度要求不高 Java、JS
- .java ——> .class 通过编译器
- java先编译,到操作系统才解释,两者特征都具有
- JDK、JRE、JVM
基础语法
注释
- 书写注释是一个非常好的习惯
- 分类:单行注释Line comment、多行注释Block comment、文档注释Java Doc
//单行注释
/*多行
注释*/
//快捷键Ctrl+D
//文档注释: /** */
/**
*@Description HelloWorld
*/
- 有趣的代码注释
标识符和关键字
- Java所有的组成部分都需要名字,类名、变量名及方法名都被称为标识符
- 标识符只能以字母(a-z,A-Z)、美元($)、下划线(_)开始
- 不能以关键字作为标识符,大小写敏感(区分大小写)
- 可以使用中文标识符,但是尽量使用英文单词作为标识符
数据类型
- Java是一种强类型语言,要求严格,所有变量都必须先定义后使用
- Java数据类型分类:
- 基本数据类型(primitive type):
- 数值类型:
- 整数:byte(1字节)、short(2字节)、int(4字节)、long(8字节)
- 浮点数:float(4字节)、double(8字节)
- 字符:char(2字节),只能一个字母、汉字
- Boolean类型:1位,true、false
- 数值类型:
- 引用数据类型(reference type):
- 类
- 接口
- 组
- 基本数据类型(primitive type):
- Long类型要在数字后面加个L
- Float类型要在数字后加个F
- String不是关键字,是一个类
- 1Byte=8bit,1024B=1KB,1024KB=1M,1024M=1G,1024G=1TB
数据类型扩展及面试讲解
- 整数拓展、进制:二进制0b,十进制,八进制0,十六进制0x
int i1=10;//10
int i2=010;//8
int i3=0x10;//16
- 浮点数拓展
- 银行业务怎么表示?:
- float(×)
- double(×)
- 浮点数的值是有限的、离散的,存在舍入误差,接近但不等于
- BigDecimal 数学工具类(√)
- 银行业务怎么表示?:
- 字符类拓展
- 所有字符本质仍然是数字
- 2字节,字符查表对应数字0-65536(2^16)
- 转义字符(\t制表符、\n换行符···)
char c1='A';//65
char c2='中';//20013
System.out.println((int)c1);
//字符强制转换成int型
char c3='\u0061';//a
- 布尔值拓展
- less is more 代码要精简易读
boolean flag = true;
if(flag==true){}
if(flag){}
类型转换
- 运算类型先转换成同一类型再进行运算
- 类型转换的分类:
- 强制类型转换(高到低) byte b=(byte)i
- 自动类型转换(低到高)
- 注意点
- 不能对boolean值进行转换
- 不能把对象类型转换为不相干类型
- 高容量到低容量要强制转换
- 转换过程中可能存在内存溢出或者精度问题
- JDK7新特性,数字之间可以用下划线分割10_0000_0000,输出时不会输出下划线
- 转换前就溢出需要先转换 long total=moneyyears ——> long total=money(long)years
变量、常量、作用域
- Java是强类型语言,每个变量都必须声明其类型
- 变量是程序中最基础的存储单元,要素包括变量名、变量类型、作用域
- 变量可以是基本类型,也可以是引用类型
- 变量作用域
- 类变量,用static修饰,与类共存亡
- 实例变量,从属于对象
- 局部变量,在方法或代码块中
- 布尔值默认是false,其余默认值是空
- 常量,程序运行过程中值不允许改变,一般使用大写
final double PI=3.14;
- 所有类成员变量、局部变量、类名、方法名应遵守首字母小写驼峰原则,常量由大写字母和下划线组成
基本运算符
- 关系运算符instanceof
- Ctrl+D复制当前行到下一行
- 二元运算符
自增自减、初识Math类
- 一元运算符
- 注意语句执行顺序
- 幂运算
Math.pow(2,3);//输出2的3次方=8
逻辑运算符、位运算符
- 与、或、非
- 逻辑运算都遵循短路运算
- 位运算
/*
A=0011 1100
B=0000 1101
A&B=0000 1100
A|B=0011 1101
A^B=0011 0001
~B=1111 0010
2*8=16 2*2*2*2
计组,效率高
<< 二进制左移 *2
>> 二进制右移 /2
*/
System.out.println(2<<3);//8
System.out.println(8<<3);//2
三元运算符
- 字符串连接符 +
int a=10;
int b=20;
System.out.println(""+a+b);//1020
System.out.println(a+b+"");//30
//字符串在前,会进行拼接;在后会进行计算
- x?y:z如果x==true则结果为y,否则为z
- 优先级()
包机制
- 包的本质是文件夹,用于区别命名空间
- 一般利用公司域名倒置来作为包名
package com.baidu.www;
import com.kuang.base.*;
//*为通配符,导入所有类
- 为了使用某一个包的成员,有时需要import导包
JavaDoc生成文档
- javadoc命令用来生成自己的API文档
/**
* @author 作者名
* @version 版本号
* @since 知名需要最早使用的JDK版本
* @return 返回值情况
* @param 参数名
* @throws 异常抛出情况
*/
public class Doc{
String name;
/**
* @param name
* @return
* @throws Exception
*/
public String test(String name) throws Exception{
return name;
}
}
//加在类上就是类的注释,加在方法上就是方法的注释
- 用命令行javadoc生成或者使用IDEA生成
流程控制
用户交互Scanner
- JDK5中的java.util.Scanner
- 实现程序和人的交互,获取用户的输入
- Scanner.hasNext 判断用户有没有输入数据
- Scanner.hasNextLine 判断用户有没有输入数据
- String str=scanner.next() 用scanner.next接收输入的数据
- String str=scanner.nextLine() 用scanner.nextLine接收输入的数据
- next()
- 一定要读取到有效字符才可以结束输入
- 对输入有效字符前的空白自动去掉
- 只有输入有效字符后的输入空白会作为分隔符或者结束符
- 不能得到带有空格的字符串
- nextLine()
- 以Enter为结束符,输入了按下回车前的所有字符
- 可以获得空白
- 凡是属于IO流的类不关闭就会一直占用资源,养成用完就关闭的好习惯scanner.close
Scanner进阶使用
- scanner.hasNextInt scanner.nextInt
- scanner.hasNextFloat scanner.nextFlotat
顺序结构
- Java的基本结构,是最简单的算法结构
if选择结构
- 分类
- 单选择
- if
- equals方法:判断字符串是否相等
- 双选择
- if ;else
- 多选择
- 一旦一个else if语句检测为true,后面的都跳过不执行
- if ;else if ;else if ;else
- 嵌套型
- 单选择
switch选择结构
- 变量类型可以是byte、short、int、char、String
- case标签必须为字符串常量或自变量
- default默认项,没有符合的case则走默认
- case具有穿透性,记得每写一个case就写一个break
- java —> class(字节码文件)———反编译(IDEA),每一个字符串对应一个哈希值
while循环结构
- 业务编程中要尽量避免死循环
- while(true)使用场景
- 等待客户端连接
- 定时检查
- ······
dowhile循环结构
- while先判断后执行,dowhile先执行后判断
- 保障程序至少能执行一次
for循环结构
- 支持迭代的一种通用结构,是最有效、最灵活的循环结构
- 迭代:每一次循环都会刷新数据,在for循环中体现为i++,i被称为迭代因子
- print不换行,println换行
嵌套for循环打印九九乘法表
public static void main(String[] args){
for(int j=1;j<=9;j++){
for(int i=1;i<=j;i++){
System.out.print(j+"*"+i+"="+(j*i)+"\t");
}
System.out.println();
}
}
增强for循环
- Java5中引入,主要用于数组
- for(声明语句:表达式)
- 声明语句:
- 声明新的局部变量,必须和数组元素类型匹配
- 作用域在循环语句块
- 值与此时数组值相等
- 表达式:要访问的数组名或者是返回值为数组的方法
- 声明语句:
break、continue、goto
- break可以控制任何循环强制退出循环,但程序没有终止
- continue终止某次循环,跳过循环中尚未执行的语句,接着进行下一次是都执行循环的判定
- 带标签的continue,outer
打印三角形及Debug
public static void main(String[] args){
for(int i=1;i<=5;i++){
for(int j=5;j>=i;j--){
System.out.print("");
}
for(int j=1;j<=i;j++){
System.out.print("*");
}
for(int j=1;j<i;j++){
System.out.print("*");
}
System.out.println();
}
}
方法
什么是方法
- 设计方法的原则:保留方法的原子性,一个方法只完成一个功能
- 命名原则:首字母小写+驼峰原则
方法的定义和调用
- 方法包含一个方法头和一个方法体
- 方法中的参数像是一个占位符,方法被调用时,传递值给参数
- 参数类型:形式参数、实参、不含参
- return 0终止方法
- 值传递(笔试题)和引用传递,Java都是值传递
方法的重载
- 重载的原则:
- 方法名必须相同
- 参数列表必须不同
- 个数不同
- 类型不同
- 参数排列顺序不同
- 返回值类型可以相同也可以不同
命令行传递参数
public static void main(String[] args){
for(int i=0;i<args.length;i++){
System.out.println("args["+i+"]:"+args[i]);
}
}
- cd../ 往上一级
- 运行class文件需要找到其包的路径
可变参数
- Java5,JDK1.5之后
- 也称为不定向参数,一个方法中只能指定一个可变参数,它必须是方法中的最后一个参数
- 在方法的声明中,在指定参数类型后加一个省略号(double… numbers)
//可以传递多个int类型的i
public void test(int... i){
System.out.println(i);
}
public static void main(String[] args){
Demo4 demo4=new Demo04();
demo04.test(1,2,3,4,5,6,7,8,9);
}
递归算法
- 递归的能力在于用有限的语句来定义对象的无限集合
- 递归结构包括两部分:
- 递归头:什么时候不调用自身。若没有,则陷入死循环
- 递归体:什么时候需要调用自身方法
- 阶乘
public static int func(int n){
if(n==1) return 1;
else return n*func(n-1);
}
- 递归三阶段:边界阶段、前阶段、返回阶段
- Java使用的是栈机制,基数不小的情况下能不用递归就要避免递归
数组
什么是数组
- 数组是最简单的数据结构,是相同类型数据的有序集合
数组的声明与创建
- dataType[] arrayRefVar = new dataType[arraySize];
- arrays.length
三种初始化及内存分析
- Java内存分析
- 堆
- 存放new的对象和数组
- 可以被所有线程共享,不会存放别的对象引用
- 栈
- 存放基本变量类型(包含具体的数值)
- 医用对象的变量(包含其在堆中的具体地址)
- 方法区
- 可以被所有的线程共享
- 包含了所有的class和static变量
- 堆
- 底层步骤
- 声明数组int[] array=null;没有赋值和创建对象,在栈的底层压入数组名array
- 创建数组array=new int[10];会在堆的空间里开辟出一个数组
- 给数组赋值,对应下标在堆中被对应赋值
- 声明时数组不会在堆中存在,创建对象时才会存在
- 三种初始化
- 静态初始化:
- 基本类型:int[] a={1,2,3};
- 引用类型:Man[] mans={new Man(),new Man()};
- 动态初始化:
- int[] arrays=new int[10];
- 默认所有值都为0,要赋值
- 默认初始化:
- 包含于动态初始化
- 创建完数组之后,未赋值,被默认隐式初始化
- 静态初始化:
数组下标越界
- 数组长度确定,一旦被创建大小不可改变
- 元素必须是相同类型
- 元素可以是任何数据类型,包括基本类型和引用类型
- 数组变量属于引用类型,数组也可以看成对象,数组中的每个元素相当于成员变量,数组本身就是对象,Java中的对象存在于堆中,因此数组无论保持原始类型还是其他对象类型,数组的对象本身存在于堆中
- 数组下标越界:java.lang.ArrayIndexOutOfBoundsException
- Ctrl+/ 快速注释
数组的使用
- 普通for循环和For-Each循环
- 打印全部数组元素
- 计算所有元素的和
- 查找最大元素
- 增强for循环,没有下标,适合打印输出,不适合操作
- 数组作方法入参
- 打印数组元素方法,数组作为参数
- 数组作返回值
- 反转数组
public static void reverse(int[] arrays){
int[] result = new int[arrays.length];
for(int i=0,j=result.length-1;i<arrays.length;i++,j--){
result[j]=arrays[i];
}
return result;//数组作为返回值
}
多维数组
- 形式
- int a[][]=new int[2][5];
- int a[][]={{1,2},{2,3}};
- 本质上是由一维数组进行数组的嵌套
int[][] array={{1,2},{2,3},{3,4},{4,5}}
/*
1,2 array[0]
2,3 array[1]
3,4 array[2]
4,5 array[3]
*/
Arrays类
- java.util.Arrays
- Arrays类中的方法都是static修饰的静态方法,在使用的时候直接使用类名调用,不能使用对象名来调用
- 常用方法
- 给数组赋值:fil
- 数组排序:sort(升序)
- 比较元素是否相等:equals
- 查找元素:binarySearch二分查找法
- 打印数组:toString
- 根据指定内容返回哈希码:hashCode
- 点进Arrays类点击左下方structure可以查看所有方法
int[] a={1,2,56,88,34,564,32};
System.out.println(a);//打印出数组对象对应的哈希值
System.out.println(Arrays.toString(a));//遍历数组并打印
Arrays.sort(a);//升序排序
Arrays.fill(a,2,4,0);//用0填充数组a2到4之间的所有元素
冒泡排序
//时间复杂度为O(n^2)
//优化后的冒泡排序
public static int[] bubbleSort(int[] array){
int temp=0;
for(int i=0;i<array.length-1;i++){
boolean flag=false;//通过flag标识减少没有意义的比较
for(int j=0;j<array.length-1-i;j++){
if(array[j]>array[j+1]){
temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
flag=true;
}
}
if(flag==false) break;
}
return array;
}
稀疏数组
- 稀疏数组是一种由压缩算法产生的数据结构,是一个二维数组
- 当一个数组中大部分元素为0,或者同一值,可以使用稀疏数组来保存该数组
- 稀疏数组的处理方式
- 记录数组一共几行几列,存在多少个不同的值
- 把具有不同值的元素和行列及值记录在一个小数组中从而缩小程序规模
- 只记录有效值的行、列、值
//创建二维数组11*11 0:没棋子 1:黑棋 2:白棋
int[][] array1=new int[11][11];
array[1][2]=1;
array[2][3]=2;
//输出原始的数组
System.out.println("输出原始的数组:");
for(int[] ints:array1){
for(int anInt:ints){
System.out.print(anInt+"\t");
}
System.out.println();
}
//转换为稀疏数组
//1.获取有效值的个数
int sum=0;
for(int i=0;i<11;i++){
for(int j=0;j<11;j++){
if(array[i][j]!=0) sum++;
}
}
//2.创建一个稀疏数组
int[][] array2=new int[sum+1][3];
//sum+1为存放多少个有效值所需要数组长度,3为行、列、值
array2[0][0]=11;//多少行
array2[0][1]=11;//多少列
array2[0][2]=sum;//多少个有效值
//遍历二维数组,将非零的值存放在稀疏数组中
int count=0;
for(int i=0;i<array1.length;i++){
for(int j=0;j<array1[i].length;j++){
if(array1[i][j]!=0){
count++;
array2[count][0]=i;//第一行存横坐标
array2[count][1]=j;//第二行存纵坐标
array2[count][2]=[i][j];//存有效值
}
}
for(int i=0;i<array2.length;i++){
System.out.println(array[i][0]+"\t"+arrar2[i][1]+"\t"+arrar2[i][2]+"\t");
}
}
//稀疏数组还原原本数组
//1.读取稀疏数组
int[][] array3=new int[array2[0][0]][array2[0][1]];
//2.给其中的元素还原其值
for(int i=1;i<array2.length;i++){//第行头部信息不用读取
array3[array2[i][0]][array2[i][1]]=array2[i][2];//横纵坐标还原
}
//3.打印
for(int[] ints:array3){
for(int anInt:ints){
System.out.print(anInt+"\t");
}
System.out.println();
}
面向对象
什么是面向对象
- Java的核心思想就是OOP面向对象编程
- 类=属性+方法
- 面向过程是线性思维,面向对象是分类思维方式
- 面向对象和面向过程不可分割
- 面向对象编程的本质:以类的方式组织代码,以对象的方式组织和封装数据
- 三大特征:封装、继承、多态
- 类是一个模板,是抽象的
- 对象是一个具体的实例,是具象的
- 对象是通过引用来进行操作的 栈——>堆(地址)
- 属性:字段field 成员变量,默认初始化 char:u0000
- 类:静态的属性、动态的方法
方法进阶
- 修饰符 返回值类型 方法名(…)
- break和return的区别
- break跳出switch、结束整个循环
- return代表方法结束,返回一个结果
- 方法命名原则:见名知意+驼峰原则
- 参数列表:可变长参数
- IO流读文件一定会抛出异常public void readFile (String file) throws IOException
- 方法分为静态方法和非静态方法
- 静态方法可以通过 类名.方法名 直接调用
- 非静态方法只有先实例化再 对象名.方法名 调用
- 同类型方法可以互相调用
- static修饰的方法类创建则存在,否则类实例化后才存在
- 实际参数和形式参数类型必须一一对应
- Java都是值传递,引用传递时传递对象,本质也是值传递
int a=1;
public static void change(int a){ a=10 ;}//a的值不会改变,因为这个a时形参,与实际a无关
public static void change(Person person){ Person.name="wch"; };
//person是一个对象:指向的时一个具体的person,可以改变属性,本质还是值传递
类与对象的创建
- 类是抽象的数据类型,是一类事物的整体描述
- 对象是抽象概念的具体实例
- 使用new关键字创建对象
- 创建时除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用
- 类中的构造器也称为构造方法,是在创建对象时必须要调用的
- 必须和类名相同
- 必须没有返回值类型,也不能用void修饰
- 一个项目中各个类中不应该有main方法,应该另起一个class文件写main方法
- this代表当前的类
- 面向对象编程的本质就是以类的方式组织代码,以对象的方式封装数据
构造器
- 类中与类名相同且没有返回值的public修饰的方法
- 一个类即使什么也不写,也会存在默认构造方法
- 作用
- 实例化一些初始值,用来初始化值
- 使用new关键字,本质是在调用构造器
- 一旦定义了有参构造器,无参就必须显式定义
- Alt+Insert 生成构造器的快捷键
创建对象内存分析
- 方法区存放类及其属性、方法、常量池,main方法压入栈底层
- 创建对象时,创建的对象名压入栈中,堆中分配一块内存进行存储(未赋值)
- 赋值后,方法区中的常量池将值赋给堆中的变量
封装
- 高内聚、低耦合
- 高内聚就是类的内部数据操作细节自己完成,不许干涉
- 低耦合就是仅暴露少量的方法给外部使用
- 应禁止直接访问一个对象的数据的实际表示,而是应该通过操作接口来访问,称为信息隐藏
- 属性私有,get/set
- private关键字修饰属性,提供一些可以操作这些属性的get/set方法
- 封装的意义
- 提高程序安全性、保护数据
- 隐藏代码的实现细节
- 统一接口,形成规范
- 提高系统的可维护性
继承
- extends关键字
- 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
- Java类中只有单继承,没有多继承
- 继承的关系是is的关系(学生继承Person,学生 is Person)
- 类与类之间的关系
- 继承
- 依赖
- 聚合
- 组合
- ···
- 子类继承父类的所有public修饰的方法和属性
- protected、default、public、private
- 快捷键 Ctrl+H 打开继承树
- Object类是所有类的父类,继承其所有的方法,在java.lang包中
super关键字
- super代表父类,this代表当前
- 子类创建时构造器会默认调用父类的构造器,隐藏了代码:super()且必须为第一行
- 注意:
- super调用父类的构造方法且必须在第一行
- super必须只能出现在子类的方法或构造方法中
- 不能和this同时调用构造方法
- this没有继承也可以使用,super只能在继承条件下使用
- this本身调用者这个对象,super代表父类对象的应用
- Ctrl+F 搜索
方法的重写
- 重写都是方法的重写,与属性无关
- 重写只对非静态的、public修饰的方法有效
- 父类的引用指向了子类
- 静态方法的调用只与左边的定义的数据类型有关
- 注解:有功能的注释
- 重写的特点
- 需要有继承关系,子类重写父类的方法
- 方法名和参数列表必须相同
- 修饰符:范围可以扩大,但不能缩小private——>protected——>default——>public
- 抛出的异常:范围可以缩小但不能扩大ClassNotFoundException——>Exception(大)
- 只有方法体不同
- 重写的意义
- 父类的功能子类不一定需要或满足
A extends B;
A a = new A();
a.test();
B b = new A();
b.test();
多态
- 动态编译,类型具有可拓展性
- 同一方法可以根据发送对象的不同而采取多种不同的行为方式
- 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多
- 多态存在的条件
- 有继承关系存在
- 子类重写父类的方法
- 父类引用指向子类的对象
- 多态指的是方法的多态,属性没有多态性
- 子类重写了父类的方法,就执行子类重写后的方法
- 对象执行的方法首先看左边对象的类型
- 父类和子类之间有联系,可以强制转换
- 类型转换异常:ClassCastException
- Father f1=new Son();
- static、final、private修饰的方法不能重写
Students extends Person;
Students s1=new Student();
Person s2=new Student();
//父类的引用指向子类,不能调用子类独有的方法,除非是子类中重写的父类方法
Object s3=new Student();
//对象执行的方法首先看左边对象的类型
instanceof和类型转换
- 前提:父类的引用指向子类的对象
- 作用:判断一个对象是什么类型
- System.out.println(X instanceof Y);取决于X和Y是否存在父子关系
- 类型之间的转换
- Person s1=new Student();
- 高(父)——>低(子) 强制转换
- Student s2=(Student)s1;
- ((Student)s1).go;
- Person person=s1;低(子)——>高(父) 自然转换,子类转父类可能会丢失一些方法
Object object=new Student();
System.out.println(object instanceof Student);//√
System.out.println(object instanceof Person);//√
System.out.println(object instanceof Object);//√
System.out.println(object instanceof Teacher);//×
System.out.println(object instanceof String);//×
static关键字
-
static修饰的变量称为静态变量又叫做类变量
-
静态变量在内存中只有一个
-
非静态方法要实例化之后才可以调用,静态方法可以直接 类名.方法名 调用
-
执行顺序:静态代码块、匿名代码块、构造方法
-
静态导入包后可以直接使用包中的方法(random、PI)
import static java.lang.Math.random;
import static java.lang.Math.PI;
-
final修饰的类断子绝孙不能被继承
public void run(){}
public static void go(){}
new Student().run;
Student.go;
抽象类
- abstract修饰符
- 修饰方法则为抽象方法
- 修饰类则为抽象类
- 只有方法名字,其他没有
- 抽象类的所有方法必须要由继承的子类重写来实现方法
- 局限性:extends的单继承
- 抽象类的特点
- 不能new抽象类的对象
- 抽象类不能实例化,只能靠子类去实现
- 抽象方法必须存在抽象类中
- 抽象类中可以写普通方法
- 抽象类不能实例化但也存在构造器
- 抽象类可以提高开发效率,可扩展性提高
public abstract class Action{
public static void say(){System.out.println("hello")};
public abstract void daSomething();//不需要写方法体
}
接口的定义与实现
- 接口只有规范(抽象方法),自己不能写方法
- 接口的本质是契约,是面向对象的精髓所在
- 声明类的关键字是class,声明接口的关键字是interface
- 接口中的方法默认为public abstract修饰的抽象方法
- 接口中的变量默认为public static final修饰的常量
- implements继承接口,可以实现 伪多继承
public interface UserService{
//自动隐藏了
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
//多继承
public class UserServiceImpl implements UserService,TimeService
{
//必须重写接口的所有方法
@override
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
内部类
- 在一个类的内部再定义一个类
- 分类
- 成员内部类
- 静态内部类
- 局部(方法)内部类
- 匿名内部类
- 通过这个外部类来实例化内部类
- 内部类可以获取外部类的私有属性、方法
- 一个java类中可以有多个class,但只能有一个public
public class outer{
private int id;
public void out(){"这是外部类的方法"};
public void out(){
class inner{ }//局部内部类
};
public class Inner{
public void in(){"这是内部类的方法"};
}
public void getID(){System.out.println(id)};
}
//通过这个外部类来实例化内部类
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
class Apple{
public void eat(){}
}
new Apple().eat();//匿名内部类
异常机制
Error类和Excepion类
- 分类
- 检查性异常
- 运行时异常
- 错误:不是异常,是脱离程序员控制的问题
- 异常处理框架的思想:把异常当作对象处理,java.lang.Throwable是所有异常类的超类
- Error类由Java虚拟机产生并抛出,大多数与程序员执行的操作无关
- RuntimeException是Exception的重要子类,一般是程序员代码有错误
捕获和抛出异常
- try、catch、finally、throw、throws
- finally主要用于善后工作,出现异常后关闭资源程序
- catch中的参数是想要捕获的异常类型
- 快捷键 Ctrl+Alt+T e.printStactTrace()打印错误的栈信息
- throw主动抛出异常,一般在方法中使用
- 假设再方法中不能处理异常,则在方法上抛出异常
- try catch好处:程序不会因为异常而停止,会继续执行
public static void main(String[] args){
int a=1;
int b=0;
try{//监控区域
Sytem.out.println(a/b);
}catch(ArithmeticException){//捕获异常
System.out.println("程序有错");
}finally{//最终处理,一定会输出结果
System.out.println("finally");
}
}
if(b==0){
throw new ArithmeticException();
}
public void test(int a,int b ) throws ArithmeticException{
//假设在方法中不能处理异常,则在方法上抛出异常
if(b==0){
throw new ArithmeticException();
}
}
自定义异常
- 自定义异常只需要继承Exception类即可
- 处理运行时异常尽量合理规避同时辅助try-catch处理
- 在多重catch块后,可以加上一个catch(Exception)处理可能遗漏的异常
- 不确定的代码也可以try-catch
- 尽量使用finally结束程序释放占用的资源
public class myException extends Exception{
//detail>10就抛出异常
private int detail;
public myException(int a){
this.detail=a;//消息
}
//toString
public String toSting(){
return "myException{"+detail+'}';
}
}
//测试类当输入大于10抛出异常