目录
补充
1. 字符串比较
==
比较两个对象的地址是否相等
equals
比较两个对象的内容是否相等例如:
String a="fsd",b="fsafsdd";
boolen od=a.equals(b);//判断a串和b串是否相等
一、基本格式
修饰符 class 类名{
代码
//类名通常用首字母大写形式
//类名和文件名必须一致
}
变量名
:由数字、字母、下划线、美元符号($)组成,不能以数字开头
二、数据类型
1、基本数据类型
整数型:short 、 int 、long、byte
浮点数:float 、double
字符型:char
布尔型:boolean
2、引用数据类型
类:class
接口:interface
数组
枚举:enum
注解:annotation
三、方法
1、方法
方法是一段可重复调用的代码。(类似于c++中的子函数)
修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2....){
return 返回值;//void没有返回值
}
2、方法的重载
在同一个作用域中,方法名相同但参数个数或者参数类型不同的方法
public class Main {
public static void main(String[] args) {
int n=add(1,2);
int m=add(1,2,3);
double p=add(1.2,1.3);
System.out.println("Hello world!");
}
//同一个方法名,不同的参数类型或个数,是允许的
public static int add(int x,int y){
return x+y;
}
public static int add(int x,int y,int z){
return x+y+z;
}
public static double add(double x,double y){
return x+y;
}
}
3、构造方法
作用: 在实例化对象的时候为变量赋值
注意:
- 构造方法名字要和类名一致
- 构造方法前不能有任何返回值类型的声明
- 不能在构造方法中
return
一个值,但是,可以单独写return
作为方法的结束
class role {
String name;
public role(String name){
this.name=name;
}
}
public class Main{
public static void main(String[] args) {
role stu=new role("宁");//调用构造方法进行初始赋值
}
}
在定义了有参构造方法之后,无参的构造方法不能在访问,即代码
class role {
String name;
public role(String name){
this.name=name;
}
}
public class Main{
public static void main(String[] args) {
role stu=new role();//调用 无参 构造方法进行初始赋值
}
}
是 错误的,如果要用无参的构造方法需要重载一个无参的构造方法,同理,构造方法可以进行多次重载
,但是要遵循构造方法的写法规范
4.静态方法
访问同静态变量一样,也可以通过实例化的对象访问
注意:
- 静态方法只能访问静态成员
- 非静态成员需要先创建对象才能访问
5.继承中方法的重写
有时需要在子类中对继承的方法进行一些修改,即对父类的方法进行重写
在子类中,重写的方法需要和父类中被重写的方法具有相同的方法名、参数列表、返回值类型!!!!!!
在重写的时候,注意:
- 子类重写父类的方法的时候,不能使用比父类更严格的访问权限,例如:父类是用
public
修饰,子类就不能用protected
以及更低的访问权限修饰
四、数组
数据类型[] 数组名;
数组名=new 数据类型[长度];//和C同样的从下标0开始
public class Main {
public static void main(String[] args) {
//初始化1
int[] x;
x=new int[100];
//初始化2
int[] y=new int[]{元素,元素....};
//初始化3
int[] z={元素,元素..};
int u=x.length;//获取数组长度
}
}
二维数组 :和一维基本相同
数据类型[][] 数组名=new 数据类型[行数][列数]
//列数不确定
数据类型[][] 数组名=new 数据类型[行数][]
//和一维的初始化2,3一样
五、类和对象
1、类
类是对象的抽象,用于描述一组对象的共同特征和行为。
类中可以定义成员变量和成员方法。
成员变量用于描述对象的特征,也被称为对象的属性
成员方法用于描述对象的行为简称对象。
class 类名{
成员变量;
成员方法;
}
class student{
//成员变量
string name;
int age=30;//成员变量
string sex;
//成员方法
void read(){
int age=50;//局部变量
System.out.println("成员方法");
}
}
允许局部变量和成员变量同名,但此时,方法中的变量值为局部变量的值,上面age就是50
2、对象(类比结构体)
类名 对象名=null;
对象名=new 类名();
//或者
类名 对象名=new 类名();
//创建好实例对象之后,可以使用了
对象名.属性名
对象名.方法名
举例:
class student{
string name;
int age;
string sex;
void read(){
System.out.println();
}
}
public class Main {
public static void main(String[] args) {
student st=new student();
}
}
六、访问控制权限
private
私有访问权限,只能在本类中访问
default
默认访问权限,如果一个类中的属性或方法没有任何访问权限的生命,则为默认访问权限,只能被本包中的类访问
protected
受保护的访问权限,只能被本本包及不同包的子类访问
public
公共访问权限,可以被所有的类访问,不论是否在同一个包中
注意:
局部变量没有访问控制权限,因为局部成员只在其所在的作用 域内起作用
七、封装性
类的封装:是指将对象的状态信息
隐藏在对象内部
,不允许外部程序直接访问
对象的内部信息,而是通过该类提供的方法实现对内部信息的访问
具体方法:在定义一个类的时候将类中的属性私有化,即使用
private
修饰,私有属性只能被本类访问
如果需要外界访问或修改,要提供公共的方法
class role{
private string name;//私有成员
public string getName() {//公有方法
return name;
}
public void setName(string name) {//公有方法
this.name = name;
}
}
public class Main{
public static void main(String[] args) {
role stu=new role();
}
}
八、关键字
1. this
如代码:
class role {
String name;
public role(String name){
this.name=name;
}
}
public class Main{
public static void main(String[] args) {
role stu=new role("宁");//调用构造方法进行初始赋值
}
}
由于name
变量不仅作为成员变量,也作为的构造方法的形参,在使用时会产生错误,所以,将本类的成员变量name
用this.name
进行调用。
this
不仅可以调用本类的成员变量,也可以在本类中调用本类的成员方法、构造方法(不是必须,条件可以的话,也可不用写this
)
在调用构造方法的时候应注意:
- 只能在构造方法中调用其他的构造方法,不能在成员方法中调用构造方法
- 在构造方法中,使用
this
调用其他构造方法是,必须位于第一行,且只能出现一次
class role {
String name;
public role(){ }
public role(String name){
this.name=name;
this.role();//错误,不在第一行
}
}
public class Main{
public static void main(String[] args) {
role stu=new role("宁");//调用构造方法进行初始赋值
}
}
- 不能在一个类的两个构造方法中使用
this
互相调用
2、static
用于修饰类的成员,如成员方法、成员变量、代码块等
如果在Java程序中用
static
修饰属性,则该属性成为静态属性(也称全局属性),可以用类名直接访问
类名.属性名
class role {
static String name="ppp";
int age;
}
public class Main{
public static void main(String[] args) {
System.out.println(role.name); //通过类名直接访问
role r1=new role(),r2=new role();
r1.age=10;
r2.age=20;
role.name="iii";
}
}
/*
如果 name 没有 static 修饰,那么不能通过类名直接访问
当 name 用 static 用修饰的时候,如果修改 name 的值, r1 和 r2 的
name 都会修改,如果没有 static 修饰,则不会同时修改
图释:
注意:
- 该关键字不能修饰局部变量
3.super
当子类重写了父类的方法后,子类对象将无法访问父类中被重写的方法,为了解决该问题,
super
便产生了
(1)使用super
访问父类的非私有属性或方法
super.属性
super.方法(参数1,参数2.....)
(2)使用super
调用父类中指定的构造方法
super(参数1,参数2.。。。);
例如:
class A {
private String name;
public A(String name){
this.name=name;
}
}
class B extends A{
int age;
public B(String name,int age){
super(name);//调用父类的构造方法
this.age=age;
}
}
public class Main{
public static void main(String[] args) {
}
}
注意:
- 使用
super
调用父类构造方法的代码必须位于子类构造方法的第一行
4. this 和 super 区别
由于这两个需要放到构造方法的首行,所以,他们不能同时出现
5. final
在默认情况下,所有的成员变量和成员方法都可以被子类重写,但是由的父类成员不希望被子类重写,那么该关键字产生了
使用
final
修饰的类不可以被继承,也就是这样的类不能派生子类
例如:
①
final class A {
}
class B extends A{
//错误,A 类是不可继承的类
}
public class Main{
public static void main(String[] args) {
}
}
②
class A {
public final void shout(){
System.out.println("balabala");
}
}
class B extends A{
public void shout(){
//错误,final 修饰的方法不能被子类重写
}
}
public class Main{
public static void main(String[] args) {
}
}
③ final
修饰的变量不能修改,类似于C语言中的const
,并且用其修饰的时候,变量名字要全部大写例如声明全局变量:
public static final int AGE=89;
6、 instanceof (判断是否为接口)
判断一个对象是否是某个类(或接口)的实例
格式:
对象 instanof 类(或接口)
上述 “ 对像 ” 如果是指定类的实例对像,则返回true
否则返回false
package PACAK1;
import javafx.scene.AmbientLight;
class Animal{
public void shout(){
System.out.println("喵喵...");
}
}
class Dog extends Animal{
//重写shout方法,不是抽象类的方法,也可以不重写,看自己需求
public void shout(){
System.out.println("汪汪汪...");
}
public void eat(){
System.out.println("不吃饭....");
}
}
public class t1 {
public static void main(String[] args) {
Animal a1=new Dog();//通过向上转型实例化 Animal 对象
System.out.println("Animal a1=new Dog():"+(a1 instanceof Animal));
System.out.println("Animal a1=new Dog():"+(a1 instanceof Dog));
Animal a2 = new Animal();
System.out.println("Animal a1=new Animal():"+(a2 instanceof Animal));
System.out.println("Animal a1=new Animal():"+(a2 instanceof Dog));
}
}
/*
输出:
Animal a1=new Dog():true
Animal a1=new Dog():true
Animal a1=new Animal():true
Animal a1=new Animal():false
*/
九、代码块
执行循序: 静态代码块 -> 构造代码块 -> 构造方法
普通代码块是在主类中第一的代码块,所以执行循序不包括该块
1.普通代码块
意思:就是直接在方法会语句中定义的代码块
错误事例:
public class Main{
public static void main(String[] args) {
{
int age=10;
System.out.println(age);
}
System.out.println(age);//错误的
}
}
正确事例:
public class Main{
public static void main(String[] args) {
{
int age=10;
System.out.println(age);
}
int age=10;
System.out.println(age);
}
}
由单纯的{}
括起来的代码为普通代码块,可以对变量起到了作用域的限定作用
2.构造块
意思:在类中定义的代码块
class role {
String name;
{
System.out.println("构造代码块");
}
}
public class Main{
public static void main(String[] args) {
role stu=new role();//调用构造方法进行初始赋值
}
}
注意:
- 构造代码块与构造方法、成员属性、成员方法同级
- 在实例化对象的时候,构造块先于构造方法执行,这个构造代码块写到前面还是后面没有关系
- 每当实例化一个对象的时候,都会先执行构造代码块,然后才会执行构造方法
3.静态代码块
使用
static
修饰的代码块
class role {
static {
System.out.println("静态代码块在此");
}
}
public class Main{
public static void main(String[] args) {
}
}
注意:
- 静态代码块只在
第一次实例化对象
的时候执行
十、继承
继承是指在一个现有的基础类上构建一个新的类,构建的新类被称为子类,现有的类称作父类,用关键字
extends
声明
class 父类名{
}
class 子类名 extends 父类名{
}
注意:
- 子类虽然可以通过继承访问父类的方法和成员,但是只能访问
public
和protected
修饰的成员和方法,对于private , default
修饰的成员和方法不能访问 - 类
只允许
单继承,不允许
多继承,如:
class A{ }
class B{ }
class c extends A,B{ }
//这种是不允许的,不可以同时继承
- 多个类
可以
继承一个父类,例如
class A{ }
class B extends A{ }
class C extends A{ }
- 多层继承也是可以的,即一个类的父类可以在继承另外的父类,如:
class A{ }
class B extends A{ }
class C extends B{ }
// c 继承了 b 类,c 是 b 的子类,b 继承了 a 类,b 是 a 的子类,同时
// c 也是 a 的子类
- 子类,父类的称呼是相对的,正如上面的:b 是 c 的父类,同时又是 a 的子类
十一、抽象类
定义一个类时,常常需要定义一些成员方法用于描述类的行为特征,但有写方法的实现是无法确定的,例如:定义一个
Animal
的父类,其中有shout()
方法(用于输出叫声),那么不同的子类(也就是不同的动物)对于shout()
方法的输出也就不同,那么父类中的shout()
方法就无法确定写法,于是abstract
关键字就诞生了
(1)抽象方法实现不需要写出方法体,例如:
abstract 返回值类型 方法名(参数1,参数2...); //注意分号别忘了写
(2)抽象类也必须用abstract
关键字修饰,语法格式:
abstract class 类名{
属性;
访问权限 返回值类型 方法名(参数....){
//普通方法
}
访问权限 abstract 返回值类型 抽象方法名(参数);
}
抽象类定义规则:
- 包含抽象方法的类必须是抽象类
- 声明抽象类和抽象方法必须用
abstract
修饰 - 抽象方法只需要声明不需要实现
- 如果一个非抽象类继承了抽象类,那么,该类必须重写抽象类中的
全部抽象方法
注意:
- 使用
abstract
修饰的抽象方法不能使用private
修饰
十二、接口
是一种用来定义程序的协议,它用于描述类或结构的一组相关行为
来源:接口是由抽象类衍生的一个概念,并由此产生了一种编程逻辑,可以称这种编程方式为
面向接口编程
面向接口编程
:将程序的不同的业务逻辑分离,以接口的形式对接
不同的业务模块。接口中不实现任何业务逻辑,业务逻辑由接口的实现类完成。当业务需求变更时,只需要修改实现类中的业务逻辑,而不需要修改接口中的内容,以减少需求变更对系统产生的影响
面向接口编程,思想类比:
鼠标,键盘等通过 USB 接口来连接计算机,如需更换只要拔掉当前的 USB 插口,换上新的即可
目的:克服单继承的限制,因为一个类只能有一个父类,而一个类可以实现多个接口,使用关键字
interface
声明
语法格式:
[public] interface 接口名 [extends 接口1,接口2...]{
[public] [static] [final] 数据类型 常量名=常量;
[public] [abstract] 返回值的数据类型 方法名(参数列表);
[public] static 返回值的数据类型 方法名(参数列表){ }
[public] default 返回值的数据类型 方法名(参数列表){ }
}
- 语法 “ extends 接口1,接口2… ” 表示一个接口可以有多个父接口,父接口之间用逗号隔开
- 接口中变量默认使用
public static final
进行修饰,即全局变量,抽象方法默认用public abstract
修饰 - 接口中无论使写不写访问权限,接口中方法的默认权限永远都是用
public
修饰
接口本身不能实例化,只能通过接口
实现类
的事例对象进行访问(抽象方法和默认方法),implements
关键字实现。实现类必须重写接口中所有的抽象方法
定义接口实现类语法:
修饰符 class 类名 implements 接口1,接口2.。。。{
}
综合应用:
//定义接口 Animal
interface Animal{
int ID=1;//定义全局常量
void shout();//定义抽象方法
}
interface Action{
public void eat();//定义抽象方法
}
//定义 Dog 类实现 Animal 接口和 Action 接口
class Dog implements Animal,Action{
public void eat(){
System.out.println("喜欢吃饭");
}
public void shout(){
System.out.println("汪汪汪");
}
}
public class Main{
public static void main(String[] args) {
Dog dog=new Dog();//创建 Dog 类的实例对象
dog.eat();//调用 Dog 类中重写的 eat() 方法
dog.shout();//调用 Dog 类中重写的 shout() 方法
}
}
补注:
- 如果一个子类既要实现接口,又要继承抽象类,则可以写为:
修饰符 class 类名 extends 父类名 implements 接口1,接口2.。。{
}
//例如:c 类继承了 A 抽象类,并实现了 B 接口
interface B{
}
abstract A{
}
class C extends A implements B{
}
- 接口不允许继承抽象类,但是允许接口继承接口
interface B{
}
interface A{
}
interface C extends A,B{ //定义 c 接口,同时继承了 A B 接口
}
class D implements C{
//定义 D 类实现 C 的接口
}
十三、多态
大意:不同类的对象在调用同一个方法时表现出来的多种不同行为
例如:定义了一个抽象类animal
,在该类中定义了一个抽象方法shout
,那么,同过定义不同的类去继承animal
类,并且重写其中的shout
方法,这样就是实现了多态
十四、对象类型的转换
向上转型:子类对象 ----> 父类对象
向下转型:父类对象 ----> 子类对象
(1)、向上转型
对象可以调用子类重写父类的方法,这样当需要添加新功能时,只需要新增一个子类,在子类中对父类的功能进行拓展,而不用更改父类的代码
更改格式:
父类类型 父类对象 = 子类实例 ;
class Animal{
public void shout(){
System.out.println("喵喵...");
}
}
class Dog extends Animal{
//重写shout方法,不是抽象类的方法,也可以不重写,看自己需求
public void shout(){
System.out.println("汪汪汪...");
}
public void eat(){
System.out.println("不吃饭....");
}
}
public class t1 {
public static void main(String[] args) {
Dog dog=new Dog(); // 创建 Dog 对象,即子类
Animal an=dog;// 完成了向上转型
an.shout(); // 输出 喵喵...
}
}
注意:
- 转型后的父类
an
无法调用Dog
中的eat()
方法,因为eat()
方法只在子类定义了
(2)、向下转型
向下转型一般是为了重新获得
因向上转型而丢失的子类特性
格式:
父类类型 父类对象 = 子类实例;
子类类型 子类对象 = (子类)父类对象;
class Animal{
public void shout(){
System.out.println("喵喵...");
}
}
class Dog extends Animal{
//重写shout方法,不是抽象类的方法,也可以不重写,看自己需求
public void shout(){
System.out.println("汪汪汪...");
}
public void eat(){
System.out.println("不吃饭....");
}
}
public class t1 {
public static void main(String[] args) {
Animal an = new Dog(); //完成了向上转型: 子类 ---> 父类
Dog dog = (Dog) an; // 向下转型
dog.shout();
dog.eat();
}
}
注意:
- 向下转型的时候,必须先进性向上转型
十五、内部类
在一个类的内部定义的类,叫做内部类
根据内部类的位置、修饰符和定义方式不同,内部类可分为:成员内部类、局部内部类、静态内部类、匿名内部类
(1)、成员内部类
内部类可以访问外部类的所有成员、无论是何种访问权限(额。。。就是类中套类)
如果想要通过外部类访问内部类,则需要通过外部类创建内部类对象,格式:
外部类名 外部类对象 = new 外部类名() ;
外部类名.内部类名 内部类对象 = 外部类对象.new 内部类名() ;
(2)、局部内部类
:也称方法内部类。在某个局部范围定义的类,他和局部变量都是在方法中定义的,有效范围只限于方法内部
可以访问外部类的所有成员变量和成员方法
如果要在外部类中访问局部内部类的成员,只能在局部内部类的所属方法中创建局部内部类的对象,通过对象访问局部内部类的额变量和方法
class Outer{
int m=0;
void tes1(){
System.out.println("外部成员方法。。。");
}
void test2(){
//定义一个局部内部类,在局部内部类中访问外部变量和方法
class Inner{
int n=1;
void shout(){
System.out.println("外部成员变量m:"+m);
tes1();
}
}
//访问局部内部类中的成员和方法
Inner inner=new Inner();
System.out.println("局部内部类变量n= "+inner.n);
inner.shout();
}
}
public class t1 {
public static void main(String[] args) {
Outer outer=new Outer();
outer.test2();
}
}
(3)、静态内部类
就是用
static
关键字修饰的成员内部类,
与成员内部类相比:多了一个
static
关键字; 静态内部类只能访问外部类的静态成员
格式:
外部类名.静态内部类 变量名 = new 外部类名.静态内部类名() ;
class Outer{
static int m=0;
static class Inner{
int n=1;
//静态内部类的方法中访问外部静态变量
void show(){
System.out.println("访问外部静态变量 m= "+m);
}
}
}
public class t1 {
public static void main(String[] args) {
Outer.Inner inner=new Outer.Inner();
inner.show();
}
}
(4)、匿名内部类
匿名内部类,就是没有名字的一种嵌套类。它是Java对类的定义方式之一。
:如果 Java 调用某个方法时、如果该方法的参数是接口类型
,那么在传参时,除了可以传入一个接口实现类,还可以传入实现接口的匿名内部类作为参数
为什么要使用匿名内部类?
在实际开发中,我们常常遇到这样的情况:一个接口/类的方法的某个实现方式在程序中只会执行一次,但为了使用它,我们需要创建它的实现类/子类去实现/重写。此时可以使用匿名内部类的方式,可以无需创建新的类,减少代码冗余
new 继承的父类或实现的接口名{
匿名内部类的类体
}
interface animal{//定义一个接口
void show();
}
public class t1 {
public static void main(String[] args) {
animalopa(new animal() { // 调用animalopa() 方法,参数为匿名内部类
@Override
public void show() {
System.out.println("miao...");
}
});
}
public static void animalopa(animal an){//该方法为接口类型
an.show();
}
}
拓展:
//具体类
class Class01 {
public void show(String s){
System.out.println("啦啦啦");
}
}
//抽象类
abstract class AbstractClass01 {
abstract void show(String s);
}
//接口
interface Interface01 {
void show(String s);
}
public class t1 {
public static void main(String[] args) {
//重写具体类的方法
new Class01(){
@Override
public void show(String s) {
System.out.println("我是一个" + s);
}
}.show("具体类");
//重写抽象类的抽象方法
new AbstractClass01(){
@Override
void show(String s) {
System.out.println("我是一个" + s);
}
}.show("抽象类");
//实现接口的抽象方法
new Interface01(){
@Override
public void show(String s) {
System.out.println("我是一个" + s);
}
}.show("接口");
}
}
输出:
我是一个具体类
我是一个抽象类
我是一个接口
对于@Override
:
@Override注解是伪代码,用于表示被标注的方法是一个重写方法。
@Override注解,只能用于标记方法,并且它只在编译期生效,不会保留在class文件中。
@Override 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Override注解标记的方法声明,如果没有覆写或者实现超类(被继承的类)的方法声明,或者不是覆写Object的public方法,那么编译就会报错。
使用@Override注解,有助于我们尽早发现这样的错误:本来想声明一个“覆写”方法,却偶然声明成“重载”方法。
使用@Override注解主要有两个好处:
1)帮助自己检查是否正确的重写父类方法
2)明显的提示看代码的人,这是重写的方法
拓展:
Lambda表达式
:只有一个带实现的抽象方法时,匿名内部类可以用Lambda表达式
表示,可以存在其他方法,其他方法必须用default
修饰
//接口
interface Animal {
void show();
}
public class t1 {
public static void main(String[] args) {
Animal stu=()->{
System.out.println("lambda方法");
} ;//相当于实例化的时候重写方法
stu.show();
}
}
如果说show()
有参数:
//接口
interface Animal {
String show(int u);
}
public class t1 {
public static void main(String[] args) {
Animal stu=(u)->{//参数类型可以不写
return u+"fsd";
} ;//相当于实例化的时候重写方法
String a=stu.show(1);
}
}
如果说show()
只有一个参数:
也可写为
//接口
interface Animal {
String show(int u);
}
public class t1 {
public static void main(String[] args) {
Animal stu=u->{ //小括号可以不写
return u+"fsd";
} ;//相当于实例化的时候重写方法
String a=stu.show(1);
}
}
如果说,方法体中只有一个返回语句
还可以在简化:
Animal stu=u->{ //小括号可以不写
return u+"fsd";
} ;//相当于实例化的时候重写方法
// 简化为
Animal stu=u-> u+"fsd";
还可以用下面的方式重写方法:
第一种:
//接口
interface Animal {
String show(int u);
}
public class t1 {
public static void main(String[] args) {
t1 a=new t1(); //因为成员方法只能具体成员调用
Animal animal=a::shoow;//对接口中的 show() 方法重写,用 shoow() 方法覆盖,名字可以相同,亦可以不相同
// 双冒号必须有,建议自己重写的方法用冒号覆盖,函数库的还可以用下面的方法
System.out.println( animal.show(2));
}
public String shoow(int p){
return "fsad";
}
}
第二种:(函数库自带的可以用)
//接口
interface Animal {
// String show(int u);
int sum(int a,int b);
}
public class t1 {
public static void main(String[] args) {
Animal animal=(a,b)->Integer.sum(a,b);//或者 = Integer::sum ;
System.out.println( animal.sum(8,2));
}
}
.
.
.
一、异常
:在程序运行时可能出现的错误或非正常情况
1.系统错误(Error)
2.编译时异常(Exception)
- 1.运行时异常(RuntimeException)
(1)抛出异常
当调用某个方法的时候 ,如果跟传入错误的参数,那么程序将无法继续运行,这个时候我们可以手动抛出一个异常来终止程序运行下去,同时告知上一级方法执行出现了问题
throw
和 throws
区别:
throw
写在方法内部,throws
跟在方法声明的后面throw
抛出的是一个异常实例,并且每次只能抛出一个,throws
后面必须加上异常类型,如果多个用逗号隔开- 声明异常的关楗字是 throws, 抛出异常的关键字是 throw
public class t1 {
public static void main(String[] args) {
System.out.println(test(1,0));
}
public static int test(int a,int b){
if(b==0)
throw new RuntimeException("除数为零");//通过 throw 抛出异常
return a/b;
}
}
运行结果:
如果说抛出了一个编译时的异常那么写为:
public static int test(int a,int b) throws Exception {//使用 throws 告知此方法会抛出那些异常,请调用方法处理
if(b==0)
throw new Exception("除数为零");
return a/b;
}
该异常会返回到调用的地方,那么调用的一方必须对该异常进行处理
如果说不同的分支会抛出不同的异常,那么必须在方法中都需要注明
public static void test(int a,int b) throws ArithmeticException,ClassCastException {//多个异常用逗号隔开
if(b==0)
throw new ArithmeticException();
else throw new ClassCastException();
}
(2)捕获异常
捕获之后程序继续执行,如果没有被捕获那么程序就会终止
如果是多个,可以继续往下写,类似于 if…else…
try{
}catch(....){
}
实例:
public class t1 {
public static void main(String[] args) {
try{
int res=divi(1,0);
System.out.println(res);
}catch (Exception e){
System.out.println("捕获的异常信息为:"+e.getMessage());
}
System.out.println("程序继续执行");
}
public static int divi(int a,int b){
int res=a/b;
return res;
}
}
运行结果:
注意:(如果抛出多个异常,并且分情况讨论的话,并且相对异常父类在前的话,所以多个情况的要注意捕获的循序)
- 抛出异常的子类会被其异常的父类捕获
如果多个异常一起打包处理的话,也可写为:
public class t1 {
public static void main(String[] args) {
try{
int res=divi(1,0);
System.out.println(res);
}catch (ArithmeticException | NegativeArraySizeException e){
System.out.println("出现了异常");
}
System.out.println("程序继续执行");
}
public static int divi(int a,int b){
int res=a/b;
return res;
}
}
finally
语句块中:放的是不管问题异常是否产生 都要执行的代码code。
try{
...
}finally{
...//无论异常是否产生 都要执行
}
//或者
try{
...
}catch{
...
}finally{
...//无论异常是否产生 都要执行
}
(3)自定义异常(对异常的方法重写)
2、工具类(Java API)
(1)数学类
Math.abs();
Math.max();
.
.
.
.
.
Math.log();// 默认 ln
Math.log10();//以10为底
//其他的用换底公式
Math.log(a)/Math.log(b);//以 b 为底 a 的对数
Math.ceil();//向上取整,不是四舍五入
Math.floor();//向下取整,不是四舍五入
(2) 数组类
int[] arr1,arr2;
Arrays.toString(数组名);//打印数组,结果形式:[1,2,3,4]
Arrays.deepToString(数组名);// 打印多维数组 结果形式:[[1,2,3,4],[1,2,3,4]]
Arrays.sort(数组名);// 从小到大排序,对浮点也可 无返回值
Arrays.fill( 数组名 , 赋值为多少); // 无返回值
Arrays.copyOf(赋值的数组 , 复制多少个 ); // 返回拷贝的数组
Arrays.copyOfRange(赋值的数组 , a , b ); // 返回拷贝的数组 区间[a,b) 下表为零开始计数
System.arraycopy(arr1 , s , arr2 , s1 , len);//无返值 从 arr1 中下表为 s 位置拷贝,到 arr2 下表为 s1 开始,拷贝了 len 个
Arrays.binarySearch(arr1 , 8);//二分查找有序数组 arr1 中值为 8 的下标,不存在返回 -1
Arrays.equals(arr1,arr2);// 一维数组 比较内容
Arrays.deepEquals(arr1,arr2);// 二维数组 比较内容
(3)字符串类
String str="fasdf";
String str1="fs";
String str2=new String();// 也可以直接 new 一个字符串
str.indexOf('x'); // 返回 字符 或 字符串 在 str 中的第一个位置
str.lastIndexOf('x'); // 返回 字符 或 字符串 在 str 中的最后一个位置
str.charAt(3); // 返回当前位置的 字符
str.equals(str1); // 比较 str 和 str1 的内容是否相同 返回 Boolean
str.isEmpty(); // 字符串如果为 0 返回true
str.toLowerCase(); // 全部转为小写
str.toUpperCase(); // 全部转为大写
str.toCharArray(); // 将 str 转为 char 数组,并返回 char 数组,应赋值(可以直接复赋值)给一个 char 数组
str.getBytes(); // 将 str 转为 byte 数组 ,和 char 数组用法一样
str.substring(l,r); // 返回 [l,r) 区间内的字符串,如果不写 r 则会从 l 到末尾
str.trim(); // 去掉当前字符串的首位空格.
String
是 final
类型的,所以一旦创建,其长度和内容是不可以改变的,他是一个常量
因此可以用 StringBuffer
类(也称字符串缓冲区)来操作字符串,他的长度和内容可以改变
StringBuffer str=new StringBuffer(); // 如果没用 new 一个对象的话,那么初始创建容量为 16, 缓冲区内不含任何内容
// 也可以直接 new 一个空间,即 new 里面是数字,缓冲区内不含任何内容
// 也可以直接 new 一个对象,缓冲区内是该对象,容量为 该对象的长度+16
str.length(); // 获取缓冲区的内容长度
str.capacity(); // 获取缓冲区的当前的容量
str.toString(); // 获取缓冲去的字符
str.append('c'); // 将参数添加到字符串中,无返回值
str.setCharAt(pos,'f'); // 修改指定索引位置的内容
str.insert(pos,"fd"); // 在 pos 的位置插入 “fd" ,无返回值
str.delete(pos); // 移除 pos 位置的字符,无返回值
str.delete(l,r); // 移除区间内字符 [ l, r )
str.reverse(); //反转字符串
StringBuffer
和 StringBuilder
基本相同
但是:
StringBuffer
是线程安全的,StringBuilder
不是,即:如果没要求线程安全,且操作大量的字符串,用StringBuilder
更快equals()
对这两种不能用,可以这样:str1.toString().equals(str2.toString())
- 这两种不能直接用
+
连接两个字符串
(4)System 类和 Runtime 类
System.exit(); // 若参数为 0 则表示异常终止
System.gc(); // 回收垃圾
System.currentTimeMillis(); // 返回的是当前时间与 1970年1月1日0:00 的时间差,单位 ms
getProperties()
和 getProperty()
方法
import java.util.Enumeration;
import java.util.Properties;
public class fsd {
public static void main(String[] args) {
Properties properties=System.getProperties(); // 获取当前系统属性
Enumeration enumeration=properties.propertyNames(); // 获取所有系统属性的键
while(enumeration.hasMoreElements()){
String key= (String) enumeration.nextElement(); // 获取系统属性的键
String value=System.getProperty(key); // 获取当前的键值
System.out.println(key+" ++++++ "+value);
}
}
}
Runtime rt=Runtime.getRuntime(); // 创建 Runtime对象
rt.exec(); // 参数为指定的可执行文件的路径
rt.freeMemory(); // 返回java虚拟机的空闲内存量,以字节为单位
rt.maxMemory(); // 返回Java虚拟机的最大可用内存量,以字节为单位
rt.availableProcessors(); // 返回java虚拟机的处理器个数
rt.totalMemory(); // 返回Java虚拟机的内存总量 ,以字节为单位
public class fsd {
public static void main(String[] args) throws Exception {
Runtime rt=Runtime.getRuntime(); // 创建 Runtime对象
Process process=rt.exec("notepad.exe"); // 打开记事本 ,得到一个 表示进程的 Process 对象
Thread.sleep(1000); // 休眠 1s
process.destroy(); // 销毁进程
}
}
(5)Random类
Random random = new Random(); // 以时间为种子,每次产生的随机数不同
int a = random.nextInt(100); // [0,100)以内的整数
// 还可以有 nextDouble() nextFloat() nextBoolean() 等
// 不写参数生成的是该类型的随机数
Random random = new Random(12);//设置指定种子,使得每次的随机数都相同
(6)BigInteger 类和 BigDecimal 类
如果需要定义一个超出int
类型的整型
数据,可以使用BigInteger
类的对象接收数据
BigInteger(String val) 将字符串 val 变为 BigInteger 类型的数据
BigInteger integer=new BigInteger("123");
BigInteger integer1=new BigInteger("345");
integer.add(integer1); // 计算和
integer.subtract(integer1); //计算与 integer1 的差
integer.multiply(integer1); // 计算 积
integer.divide(integer1); // 计算与 integer1 商
BigInteger res[]=integer.divideAndRemainder(integer1); // 计算与 integer 的商,第一个位置为 商 ,第二个位置为 余数
BigDecimal
多用于数据精度高的地方,因为 double
和float
容易丢失精度、
用法和BigInteger
基本一样,多了
BigDecimal d=BigDecimal.valueOf(0.99); // 可以将 double 类型的数转为 BigDecimal
(7)日期类
(8)包装类
3、I/O
(1)、File类
File(); 参数为路径,根据指定路径创建一个File对像,可以为2个参数,具体参考样例
File file = new File("E://test//Test.txt");
//可以写为
File parent = new File("E://test");
File file = new File(parent,"Test.txt");
常用方法
boolean te=file.exists();// 判断文件是否存在
boolean te=file.delete();// 如果删除文件成功则返回 true
boolean te=file.createNewFile();// 当前文件不存在时,创建一个新文件,成功返回true
boolean te=file.canWrite();// 判断文件是否可读,可读返回true
boolean te=file.isDirectory();//判断File对象是否是目录
String name=file.getName();// 返回文件的名字
String path=file.getPath();// 返回文件的路径(相对路径)
String patha=file.getAbsolutePath();// 返回绝对路径
long time=file.lastModified();// 返回文件的最后修改时间
long tie=file.length(); // 返回文件的字节长度
有时候需要用到一些临时文件:
File file=File.createTempFile("te",".txt");// 文件的名字和后缀
file.deleteOnExit();// 在推出虚拟机后自动删除
(2)字节流
FileInputStream
是文件字节输入流
InputStream
是字节输入流
前者是后者的子类
用法基本相同
1.
FileInputStream fileInputStream=new FileInputStream("te.txt");// 文件字节输入流
int b=0;
while((b=fileInputStream.read())!=-1){//每次读取一个字节,当等与-1 表示文件读取完毕,读取会返回一个0~255的整数
System.out.println(b);
}
byte[] buf = new byte[1024];
/**
* 读取数据,读取缓冲区指定大小的数据
* 返回实际读取字节的数量(长度),如果未读取到数据则返回-1
*/
int len = - 1;
//循环读取文件中的数据,当len的值为-1时表示读取结束
while((len=fileInputStream.read(buf,0,buf.length))!=-1){
/**
* 将字节数组中的字节转换字符串
* 指定转换的起始下标,及转换长度
*/
String str = new String(buf,0,len);
System.out.println(str);
}
输出流(OutputStream
)
void write(int b); // 写入一个字节
void write(byte[] b);// 写入指定的字节数组
void write(byte[] b,int off ,int len);// 从 off 开始的len字节写入
void flush();// OutputStream 类的方法,刷新输出流,并强制写出所有缓冲的输出字节
void close();// 输入/输出 关闭输入/输出流
(3) 字符流
FileReader
输入流
FileWriter
输出流
int read();// 以字符为单位读取数据
int read(char cbuf[]); // 将数据读入char类型的数组,并返回数据长度
int read(char cbuf[],int star,int len); // 将数据读入char类型的数组,并返回数据长度,从star开始写len个
long transferTo(Writer out);// 将数据直接读入字符输出流
void write();// 以字符为单位写入数据
void write(char cbuf[]);
void write(char cbuf[],int star,int len);
void wirte(String str); // 将String类型的数据写出
void wirte(String str,int star,int len);// 指定str的区间
void flush();// 只有输出流有
void close();