Java SE基础知识详解第[9]期—面向对象进阶(多态、内部类、常用API)

简介: Java SE基础知识详解第[9]期—面向对象进阶(多态、内部类、常用API)

面向对象进阶(多态、内部类、常用API)

1.面向对象三大特征之三:多态

1.1多态的概述,多态的形式

什么是多态?

同类型的对象,执行同一个行为,会表现出不同的行为特征。

多态的常见形式

父类类型 对象名称 = new 子类构造器;

接口 对象名称 = new 实现类构造器;

多态中成员访问特点

方法调用:编译看等号左边,运行看等号右边。

变量调用:编译看左边,运行也看左边。(多态侧重行为多态)

示例代码如下:

动物类

publicabstractclassAnimal {
publicStringname="父类动物";
publicabstractvoidrun();
}

狗类

publicclassDogextendsAnimal{
publicStringname="子类狗";
@Overridepublicvoidrun() {
System.out.println("狗跑得快");
    }
}

乌龟类

publicclassTortoiseextendsAnimal{
publicStringname="子类乌龟";
@Overridepublicvoidrun() {
System.out.println("乌龟跑得慢");
    }
}

测试类

publicclassTest {
publicstaticvoidmain(String[] args) {
// 1.多态的形式  父类类型 对象名称 = new 子类构造器;Animaldog=newDog();
dog.run(); // 狗跑得快  方法调用:编译看左边,运行看右边System.out.println(dog.name); // 父类动物   变量调用:编译看左边,运行也看左边(多态侧重行为多态)Animaltortoise=newTortoise();
tortoise.run(); // 乌龟跑得慢System.out.println(tortoise.name); // 父类动物    }
}

多态的前提

有继承/实现关系;有父类引用指向子类对象;有方法重写。

1.2多态的好处

在多态形式下,右边对象可以实现解耦合,便于扩展和维护。

Polymorphic.png

定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的扩展性与便利性。

多态下会产生的一个问题

编译看左边,等号左边父类中没有子类的独有功能,编译不通过,因此多态下不能使用子类的独有功能,为了解决此问题,需要进行强制类型转换。

1.3多态下引用数据类型的类型转换

自动类型转换(从子到父):子类对象赋值给父类类型的变量指向。

强制类型转换(从父到子):

此时必须进行强制类型转换:子类 对象变量 = (子类)父类类型的变量

作用:可以解决多态下的劣势,可以实现调用子类独有的功能。

注意:如果转型后的类型和对象真实类型不是同一种类型,有继承或实现关系,在编译阶段,语法上可以强制类型转换,但是在运行实际转换的时候会出现ClassCastException错误

因此在强制转换前使用instanceof判断当前对象的真实类型,再进行强制转换。

格式为:变量名 instanceof 真实类型 

判断关键字左边的变量指向的对象的真实类型是否是右边的类型或者是其子类类型,是则返回true,反之返回false。

示例代码如下:

动物类

publicabstractclassAnimal {
publicabstractvoidrun();
}

狗类

publicclassDogextendsAnimal{
@Overridepublicvoidrun() {
System.out.println("狗跑得快");
    }
/*独有功能*/publicvoidlookDoor() {
System.out.println("狗看门");
    }
}

乌龟类

publicclassTortoiseextendsAnimal{
@Overridepublicvoidrun() {
System.out.println("乌龟跑得慢");
    }
/*独有方法*/publicvoidlayEggs() {
System.out.println("乌龟会下蛋");
    }
}

测试类

publicclassTest {
publicstaticvoidmain(String[] args) {
// 自动类型转换Animala=newDog();
a.run();
// 强制类型转换   子类 对象变量 = (子类)父类类型的变量Animala2=newTortoise();
a2.run();
Tortoiset= (Tortoise) a2; // 从父类类型到子类类型必须进行强制类型转换t.layEggs();
// 如果转型后的类型和对象真实类型不是同一种类型,那么在转换的时候就会出现ClassCastException//        Dog d = (Dog)a2; // 报错,转型后的类型与真实类型不同// 在强制转换前使用instanceof判断当前对象的真实类型,再进行强制转换if (a2instanceofDog) { // 若a2指向的对象为Dog类型,则强制转换为Dog类型Dogd= (Dog) a2;
d.lookDoor();
        } elseif (a2instanceofTortoise) { // 若a2指向的对象为Tortoise类型,则强制转换为Tortoise类型Tortoiset2= (Tortoise) a2;
t2.layEggs();
        }
    }
}

程序运行结果如下:

狗跑得快

乌龟跑得慢

乌龟会下蛋

乌龟会下蛋

1.4多态的综合案例

需求:

使用面向对象编程模拟:设计一个电脑对象,可以安装2个USB设备

鼠标:被安装时可以完成接入、调用点击功能、拔出功能。

键盘:被安装时可以完成接入、调用打字功能、拔出功能。

分析:

①定义一个USB的接口(申明USB设备的规范必须是:可以接入和拔出)。

②提供2个USB实现类代表鼠标和键盘,让其实现USB接口,并分别定义独有功能。

③创建电脑对象,创建2个USB实现类对象,分别安装到电脑中并触发功能的执行。

示例代码如下:

USB接口:

publicinterfaceUSB {
// 接入、拔出voidconnect();
voidunconnect();
}

Mouse类

publicclassMouseimplementsUSB{
privateStringname;
publicMouse() {
    }
publicMouse(Stringname) {
this.name=name;
    }
@Overridepublicvoidconnect() {
System.out.println(name+"鼠标成功连接");
    }
@Overridepublicvoidunconnect() {
System.out.println(name+"鼠标成功断开");
    }
/*独有功能*/publicvoidclick() {
System.out.println("鼠标点击");
    }
}

KeyBoard类

publicclassKeyBoardimplementsUSB{
privateStringname;
publicKeyBoard() {
    }
publicKeyBoard(Stringname) {
this.name=name;
    }
@Overridepublicvoidconnect() {
System.out.println(name+"键盘成功连接");
    }
@Overridepublicvoidunconnect() {
System.out.println(name+"键盘成功断开");
    }
/*独有功能*/publicvoidkeyDown() {
System.out.println("键盘打字");
    }
publicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
this.name=name;
    }
}

Computer类

publicclassComputer {
privateStringname;
publicComputer() {
    }
publicComputer(Stringname) {
this.name=name;
    }
publicvoidstart() {
System.out.println(name+"电脑开机了");
    }
/*提供安装USB设备的入口*/publicvoidinstallUSB(USBusb) { // 父类接口作为入参,所有实现类对象均可作为参数传入usb.connect(); // USB设备的通用功能// 不同设备的独有功能:先判断、再强转if (usbinstanceofKeyBoard) {
KeyBoardkeyBoard= (KeyBoard) usb;
keyBoard.keyDown(); // 调用键盘的独有功能        } elseif (usbinstanceofMouse) {
Mousemouse= (Mouse) usb;
mouse.click(); // 调用鼠标的独有功能        }
usb.unconnect(); // USB设备的通用功能    }
}

测试类

publicclassTest {
publicstaticvoidmain(String[] args) {
// 创建电脑对象Computercomputer=newComputer("麦本本");
computer.start();
// 创建鼠标、键盘对象USBu=newKeyBoard("deiog");
computer.installUSB(u);
System.out.println("--------");
USBu2=newMouse("X2");
computer.installUSB(u2);
    }
}

程序运行结果如下:

麦本本电脑开机了

deiog键盘成功连接

键盘打字

deiog键盘成功断开

--------

X2鼠标成功连接

鼠标点击

X2鼠标成功断开

2.内部类

2.1内部类概述

内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主)。

其定义格式如下图所示。

InnerClass.png

内部类的使用场景、作用

当一个类的内部还有一个部分需要一个完整的结构进行描述(如汽车类中的发动机类、人类中的心脏类等),而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构可以选择使用内部类来设计。

内部类通常可以方便访问外部类的成员,包括私有的成员。

内部类提供了更好的封装性,内部类本身就可以用private protectecd等修饰,封装性可以做更多控制。

2.2内部类之一:静态内部类[了解]

什么是静态内部类?

有static修饰,属于外部类本身。

它的特点和使用与普通类是完全一样的,类有的成分它都有,只是位置在里面而已。

静态内部类定义格式如下图所示:

StaticInnerClass.png

静态内部类创建对象的格式

格式:外部类名.内部类名 对象名 = new 外部类名.内部类构造器;

范例:Outer.Inner in = new Outer.Inner();

静态内部类中是否可以直接访问外部类的静态成员?

可以,外部类的静态成员只有一份可以被共享访问。

静态内部类中是否可以直接访问外部类的实例成员?

不可以,外部类的实例成员必须用外部类对象访问。

示例代码如下图所示:

/*外部类*/publicclassOuter {
publicstaticintage=18;
privateStringhobby;
/*内部类*/publicstaticclassInner {
privateStringname;
publicstaticStringSchoolName;
publicInner() {
        }
publicInner(Stringname) {
this.name=name;
        }
publicvoidshow() {
System.out.println("名称:"+name);
System.out.println(age); // 静态内部类中可以直接访问外部类的静态成员,外部类的静态成员只有一份可以被共享访问//            System.out.println(hobby); // 报错,静态内部类中不可以直接访问外部类的实例成员,必须用外部类对象间接访问Outerouter=newOuter();
System.out.println(outer.hobby); // 外部类的实例成员属于对象,在使用时必须创建对象才能访问        }
publicStringgetName() {
returnname;
        }
publicvoidsetName(Stringname) {
this.name=name;
        }
    }
}

2.3内部类之二:成员内部类[了解]

什么是成员内部类?

无static修饰,属于外部类的对象。

JDK16之前,成员内部类中不能定义静态成员,JDK 16开始也可以定义静态成员了。

成员内部类创建对象的格式

格式:外部类名.内部类名 对象名 = new 外部类构造器.new 内部类构造器;

范例:Outer.Inner in = new Outer().new Inner();

成员内部类中是否可以直接访问外部类的静态成员?

可以,外部类的静态成员只有一份可以被共享访问。

成员内部类的实例方法中是否可以直接访问外部类的实例成员?

可以,因为必须先有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员。

在成员内部类中访问所在外部类对象

格式:外部类名.this

示例代码如下所示:

classPeople {
privateintheartbeat=150;
publicclassHeart {
privateintheartbeat=110;
publicvoidshow() {
intheartbeat=78;
System.out.println(heartbeat); // 78System.out.println(this.heartbeat); // 110System.out.println(People.this.heartbeat); // 150        }
    }
}

2.4内部类之三:局部内部类[了解]

局部内部类(鸡肋语法,了解即可)

局部内部类放在方法、代码块、构造器等执行体中。

局部内部类的类文件名为:外部类$N内部类.class

2.5内部类之四:匿名内部类概述[重点]

什么是匿名内部类?

本质上是一个没有名字的局部内部类,定义在方法中、代码块中等。

作用:方便创建子类对象,最终目的为了简化代码编写。

匿名内部类的格式:

AnonymousInnerClass.png

采用匿名内部类的形式,特点总结:

匿名内部类是一个没有名字的内部类。

匿名内部类写出来就会产生一个匿名内部类的对象

匿名内部类的对象类型相当于是当前new的那个的类型的子类类型,无需构建子类,直接重写方法,省去子类继承、子类中方法重写的步骤。

示例代码如下:

publicclassTest {
publicstaticvoidmain(String[] args) {
// 原方式:构建子类,继承,创建子类对象,调用方法//        Animal animal = new Tiger();//        animal.run(); // 老虎跑得快// 采用匿名内部类的形式,无需构建子类,直接重写方法,省去子类继承、子类中方法重写的步骤Animalanimal=newAnimal() {
@Overridepublicvoidrun() {
System.out.println("老虎跑得快");
            }
        };
animal.run(); // 老虎跑得快    }
}
abstractclassAnimal {
publicabstractvoidrun();
}
//class Tiger extends Animal {//    @Override//    public void run() {//        System.out.println("老虎跑得快");//    }//}

匿名内部类常见使用形式

需求:某个学校需要让老师,学生,运动员一起参加游泳比赛

示例代码如下:

publicclassTest2 {
publicstaticvoidmain(String[] args) {
Swimmings1=newSwimming() {
@Overridepublicvoidswim() {
System.out.println("学生游泳");
            }
        };
go(s1);
System.out.println("------");
// 匿名内部类可以作为方法的实际参数进行传输go(newSwimming() { // 省略创建变量的步骤,直接将匿名内部类对象指向作为参数传入@Overridepublicvoidswim() {
System.out.println("老师游泳");
            }
        });
    }
/*** 需求:学生、老师可以一起参加游泳比赛*/publicstaticvoidgo(Swimmings) {
System.out.println("开始");
s.swim();
System.out.println("结束");
    }
}
interfaceSwimming {
voidswim();
}

程序运行结果如下:

开始

学生游泳

结束

------

开始

老师游泳

结束

注:匿名内部类可以作为方法的实际参数进行传输。

2.6匿名内部类真实使用场景演示

如下图所示,给按钮绑定点击事件。

AnonymousInnerClassDemo.png

示例代码如下:

publicclassTest3 {
publicstaticvoidmain(String[] args) {
// 1.创建窗口JFramewin=newJFrame("登陆界面");
JPanelpanel=newJPanel();
win.add(panel);
// 2.创建一个按钮对象JButtonbtn=newJButton("登陆");
// 绑定监听器(监听是否点击按钮)btn.addActionListener(newAbstractAction() {
@OverridepublicvoidactionPerformed(ActionEvente) {
JOptionPane.showMessageDialog(win, "点击");
            }
        });
// 最简化的代码   内部类的目的是简化代码//        btn.addActionListener(e -> JOptionPane.showMessageDialog(win, "点击"));// 3.把按钮对象添加到桌布中展示panel.add(btn);
// 4.展示窗口win.setSize(400, 300);
win.setLocationRelativeTo(null);
win.setVisible(true);
    }
}

使用总结:开发中不是我们主动去定义匿名内部类的,而是别人需要我们写或者我们可以写的时候才会使用。匿名内部类的代码可以实现代码进一步的简化。

3常用API

什么是API?

API(Application Programming interface) 应用程序编程接口。简单来说:就是Java帮我们已经写好的一些方法,我们直接拿过来用就可以了。

3.1Object

Object类的作用

一个类要么默认继承了Object类,要么间接继承了Object类,Object类是Java中的祖宗类。

Object类的方法是一切子类对象都可以直接使用的。

Object类的常用方法

方法名

说明

public String toString()

默认是返回当前对象在堆内存中的地址信息:

类的全限名(从包名开始)@内存地址(16进制的地址)

public boolean equals(Object o)

默认是比较当前对象与另一个对象的地址是否相同

相同返回true,不同返回false

(1)toString()

问题引出

开发中直接输出对象,默认输出对象的地址其实是毫无意义的,开发中输出对象变量,更多的时候是希望看到对象的内容数据而不是对象的地址信息。

toString存在的意义

父类toString()方法存在的意义就是为了被子类重写,以便返回对象的内容信息,而不是地址信息。

子类快速重写toString()方法

①如下图所示,在子类中右键空白处,点击【生成】。

Generate.png

②如下图所示,在弹出的菜单栏中选择【toString()】,一键重写toString方法。

toString().png

③如下图所示,在弹出的页面中选择对象中要打印的内容信息(默认全选),选择完毕后,点击确认即可,此时在调用时,打印的是对象中的内容信息而不是堆内存中的地址信息。

GenerateToString.png

toString()重写方法示例代码如下:

@OverridepublicStringtoString() {
return"Student{"+"name='"+name+'\''+", sex="+sex+", age="+age+'}';
    }

(2)equals(Object o)

问题引出

直接比较两个对象的地址是否相同完全可以用“==”替代equals。

equals存在的意义

父类equals方法存在的意义就是为了被子类重写,以便子类自己来定制比较规则

子类快速重写equals()方法

①如下图所示,在子类中右键空白处,点击【生成】。

Generate.png

②如下图所示,在弹出的菜单栏中选择【equals()和hashCode()】,一键重写equals()方法。

Equals().png

③在弹出的页面中,信息保持默认,选择【下一个】->【完成】,此时在调用时,比对的是对象中的内容信息而不是堆内存中的地址信息。

toString()方法重写与equals()方法重写示例代码如下:

publicclassStudent { // 所有的类都直接或间接继承Object类privateStringname;
privatecharsex;
privateintage;
publicStudent() {
    }
publicStudent(Stringname, charsex, intage) {
this.name=name;
this.sex=sex;
this.age=age;
    }
/*重写toString()方法*/// 自动生成@OverridepublicStringtoString() {
return"Student{"+"name='"+name+'\''+", sex="+sex+", age="+age+'}';
    }
/*重写equals(Object o)方法若两个对象内容一样,则认为二者相等*//*    @Overridepublic boolean equals(Object obj) {// 1.判断o是不是学生类型if (obj instanceof Student) {// name、char、sex是Student中独有的属性,需要将obj进行强制类型转换,否则无法访问Student独有属性Student stu = (Student) obj;// 2.判断两个对象的内容是否一致//            if (this.name.equals(stu.name) & (this.sex == stu.sex) & (this.age == stu.age)) {//                return true; // 判断完成,所有的值均相同,返回true//            } else {//                return false; // 至少有一项的值不相同,返回false//            }return this.name.equals(stu.name) & (this.sex == stu.sex) & (this.age == stu.age);} else {return false; // 学生类只能与学生类比较,否则为false}}*/// 自动生成@Overridepublicbooleanequals(Objecto) {
// 判断两个对象是否是同一对象(地址是否相同)if (this==o) returntrue;
// 判断传入的对象是否为空 || 当前this对象与传入的对象类型是否不同  若有一个为真,则返回false getClass():取类型if (o==null||getClass() !=o.getClass()) returnfalse;
// 判断完毕,开始比对Studentstudent= (Student) o;
returnsex==student.sex&&age==student.age&&Objects.equals(name, student.name);
    }
@OverridepublicinthashCode() {
returnObjects.hash(name, sex, age);
    }
// getter、setter方法}

3.2Objects

Objects是一个工具类,提供了一些方法去完成一些功能。

Objects类的常用方法

方法名

说明

public static boolean equals(Object a, Object b)

比较两个对象,底层会先进行非空判断,再进行equals比较

Objects(a, b)比较结果同a.equals(b),但是其避免了空指针异常,更安全。

public static boolean isNull(Object obj)

判断变量是否为null ,为null返回true ,

否则返回false。

Objects.isNull(a)等同于a == null

 

3.3StringBuilder

StringBuilder概述

StringBuilder是一个可变的字符串类,我们可以把它看成是一个对象容器。

作用:提高字符串的操作效率,如拼接、修改等。

StringBuilder构造器

名称

说明

public StringBuilder()

创建一个空白的可变的字符串对象,不包含任何内容

public StringBuilder(String str)

创建一个指定字符串内容的可变字符串对象

 

StringBuilder常用方法

方法名称

说明

public StringBuilder append

(任意类型)

添加数据并返回StringBuilder对象本身

public StringBuilder reverse()

将对象的内容反转

public int length()

返回对象内容长度

public String toString()

通过toString()就可以实现把StringBuilder转换为 String

 

示例代码如下:

publicclassStringBuilderDemo1 {
publicstaticvoidmain(String[] args) {
StringBuildersb=newStringBuilder();
sb.append("a");
sb.append("b");
sb.append("c");
sb.append("d");
sb.append("123");
System.out.println(sb); // abcd123StringBuildersb2=newStringBuilder();
// 支持链式编程sb2.append("a").append("b").append("c").append("张三李四");
System.out.println(sb2); // abc张三李四// 内容反转sb2.reverse().append("d");
System.out.println(sb2); // 四李三张cbad// 获取对象内容长度intlength=sb2.length();
System.out.println(length); // 8// StringBuilder只是拼接字符串的手段,Java行业规范主要使用String类型,因此最终仍然要转换为String类型// 把StringBuilder类型数据转换为String类型数据Stringrs=sb2.toString();
System.out.println(rs); // 四李三张cbad 此时数据为String类型    }
}

注:StringBuilder类型数据支持链式编程,可以连续多次使用append()方法拼接字符串,如sb.append("a").append("b").append("c").append("张三李四");

StringBuilder提高效率原理

String类拼接字符串原理如下图所示。

String.png 

其内存机制执行步骤如下:

Step1:在栈内存中执行main方法。执行代码第一行,在栈内存中生成String类型变量s1,用来存储在堆内存的常量池中生成字符串a的地址值。

Step2:执行代码第二行,在堆内存中new一个StringBuilder对象(String类型底层也是基于StringBuilder类型运算的),将s1指向的值a与常量池中生成的字符串b拼接到该StringBuilder对象中,再通过toString()将数据类型转换成String类型,再将该对象的地址值存储到栈内存中生成的String类型变量s2中(s2指向该字符串对象)。

Step3:同理,执行第三行代码。

Step4:执行第4行代码,将String类型变量s3内存储的堆内存中的字符串对象打印出来。

存在问题:

String是不可变的字符串类型,每次进行字符串拼接时,都要new出一个StringBuilder对象和一个String对象,且在拼接过程中不断地丢弃之前的对象,十分浪费内存空间。

StringBuilder类拼接字符串原理如下图所示。

StringBuilder.png

采用StringBuilder拼接字符串对象只会在堆内存中new一个StringBuilder对象,用于存储拼接的字符串,并其将地址存储到栈内存中生成的StringBuilder变量中。拼接过程中直接将常量池中的abc字符串对象拼接到对象中,中途不会产生额外对象,节省内存空间,提高效率。

案例—打印整型数组内容

需求:设计一个方法用于将任意整型数组的内容输出为字符串,要求输出成如下格式:“该数组内容为:[11, 22, 33, 44, 55]

分析:

1、定义一个方法,要求该方法能够接收数组,并输出数组内容。

2、定义一个静态初始化的数组,调用该方法,并传入该数组。

示例代码如下:

publicclassStringBuilderTest2 {
publicstaticvoidmain(String[] args) {
int[] arr1=null;
System.out.println(toString(arr1)); // nullint[] arr2= {};
System.out.println(toString(arr2)); // 该数组内容为:[]int[] arr3= {10, 2, 30, 888};
System.out.println(toString(arr3)); // 该数组内容为:[10,2,30,888]    }
// 1.定义方法接收任意整型数组,返回数组内容publicstaticStringtoString(int[] arr) {
// 判断数组是否为nullif (Objects.isNull(arr)) {
returnnull; // 若是null,则不进行拼接,直接返回null        }
// 2.开始拼接内容StringBuildersb=newStringBuilder("该数组内容为:[");
for (inti=0; i<arr.length; i++) {
sb.append(arr[i]).append(i==arr.length-1?"" : ",");
        }
sb.append("]");
returnsb.toString(); // 拼接结束后将StringBuilder类型对象转换为String类型并返回    }
}

一句话总结StringBuilder与String:StringBuilder是拼接字符串的手段,String是目的(最后需要转换为String类型)。

3.4Math

Math类概述

包含执行基本数字运算的方法,Math类没有提供公开的构造器(不能创建对象)

Math严格讲属于工具类,成员都是静态的,通过类名就可以直接调用

Math类的常用方法

方法名

说明

public static int abs (int a)

获取参数绝对值

public static double ceil (double a)

向上取整

public static double floor (double a)

向下取整

public static int round (float a)

四舍五入

public static int max (int a,int b)

获取两个int值中的较大值

public static double pow (double a,double b)

返回a的b次幂的值

public static double random ()

返回值为double的随机值,范围[0.0,1.0)

 

示例代码如下:

publicclassMathDemo {
publicstaticvoidmain(String[] args) {
//        1.    public static int abs (int a)   获取参数绝对值System.out.println(Math.abs(10.3)); // 10.3System.out.println(Math.abs(-9)); // 9System.out.println("--------");
//        2.    public static double ceil (double a)    向上取整System.out.println(Math.ceil(2.5)); // 3.0System.out.println(Math.ceil(-3)); // -3.0System.out.println("--------");
//        3.    public static double floor (double a)   向下取整System.out.println(Math.floor(3.9)); // 3.0System.out.println(Math.floor(-1.8)); // -2.0System.out.println("--------");
//        4.    public static int round (float a)   四舍五入System.out.println(Math.round(4.4999999)); // 4System.out.println(Math.round(5.5)); // 6System.out.println("--------");
//        5.    public static int max (int a,int b) 获取两个int值中的较大值System.out.println(Math.max(35, 56)); // 56System.out.println("--------");
//        6.    public static double pow (double a,double b)    返回a的b次幂的值System.out.println(Math.pow(2, 4)); // 16.0System.out.println(Math.pow(3, 2)); // 9.0System.out.println("--------");
//        7.    public static double random ()  返回值为double的随机值,范围[0.0,1.0)System.out.println(Math.random()); // 0.0-1.0(左闭右开)之间的一个随机数System.out.println("--------");
// 拓展:生成 3 - 9 之间的随机数   ( 0 + 6 ) + 3// [0,6] + 3intdate= (int) ((Math.random() *7) +3);
// Math.random()--> [0,1)   (Math.random() * 6)-->[0,6) 不满足[0,6]// 因此必须(Math.random() * 7)-->[0,7),然后进行int类型强制转换,丢弃 >= 6的数字的小数部分,强制转为6// 但是个人认为,这样并不是随机生成,这样会导致 >= 6的数字全变为6,提高了6的出现可能性,并不是随机    }
}

3.5System

System是一个工具类,代表了当前系统,提供了一些与系统相关的方法

System类的常用方法

方法名

说明

public static void exit(int status)

终止当前运行的 Java 虚拟机(JVM),非零表示异常终止

public static long currentTimeMillis()

返回从1970-1-1 0:00 走到到此刻总的毫秒值

返回当前系统的时间毫秒值形式

public static void arraycopy

(数据源数组,起始索引,目的地数组, 起始索引,拷贝个数)

数组拷贝

 

示例代码如下:

publicclassSystemDemo {
publicstaticvoidmain(String[] args) {
System.out.println("程序开始");
//        public static void exit(int status)   终止当前运行的 Java 虚拟机,非零表示异常终止//        System.exit(0); // JVM终止//        public static long currentTimeMillis()    返回从1970-1-1 0:00 走到到此刻总的毫秒值 返回当前系统的时间毫秒值形式//        long time = System.currentTimeMillis();//        System.out.println(time);// 进行时间计算:性能分析//        long startTime = System.currentTimeMillis();//        for (int i = 0; i < 100000; i++) {//            System.out.println("输出:" + i);//        }//        long endTime = System.currentTimeMillis();//        System.out.println((endTime - startTime) / 1000.0);//        public static void arraycopy  (数据源数组,起始索引,目的地数组, 起始索引,拷贝个数)   数组拷贝/* arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length);参数一:被拷贝的数组参数二:开始复制的索引参数三:拷贝的目标数组参数四:开始粘贴的索引参数五:拷贝元素长度(个数)*/int[] arr1= {10, 20, 30, 40, 50, 60, 70};
int[] arr2=newint[6]; // [0, 0, 0, 0, 0, 0] --> [0, 0, 40, 50, 60, 0]System.arraycopy(arr1, 3, arr2, 2, 3);
// 把任意数组的内容转换为String类型并返回Stringrs=Arrays.toString(arr2);
System.out.println(rs);
System.out.println("程序结束");
    }
}

3.6BigDecimal

如下图所示,浮点型运算的时候直接+ * / 可能会出现数据失真(精度问题)。

AccuracyDistortion.png

BigDecimal作用:用于解决浮点型运算精度失真问题。

使用方法:创建对象BigDecimal封装浮点型数据(最好的方式是调用方法)。

public static BigDecimal valueOf(double val); 包装浮点数成为BigDecimal对象。

BigDecima常用API

方法名

说明

public BigDecimal add(BigDecimal b)

加法

public BigDecimal subtract(BigDecimal b)

减法

public BigDecimal multiply(BigDecimal b)

乘法

public BigDecimal divide(BigDecimal b)

除法

public BigDecimal divide (另一个BigDecimal对象,精确几位,舍入模式)

除法

 

示例代码如下:

publicclassBigDecimalDemo {
publicstaticvoidmain(String[] args) {
// 浮点型运算的时候直接+ * / 可能会出现数据失真(精度问题)。System.out.println(0.09+0.01); // 0.09999999999999999System.out.println(1.0-0.32); // 0.6799999999999999System.out.println(1.015*100); // 101.49999999999999System.out.println(1.301/100); // 0.013009999999999999doublec=0.1+0.2;
System.out.println(c); // 0.30000000000000004System.out.println("-------------------------");
// 包装浮点数成为BigDecimal对象//        BigDecimal d1 = new BigDecimal(0.1); // 仍然会出现精读问题,不推荐使用BigDecimald1=BigDecimal.valueOf(0.1);
BigDecimald2=BigDecimal.valueOf(0.2);
System.out.println("------加法------");
BigDecimald=d1.add(d2); // 调用BigDecimal对象的add方法System.out.println(d); // 0.3   重写了toString方法,打印内容而不是地址System.out.println("------减法------");
BigDecimale=d1.subtract(d2); // -0.1System.out.println(e);
System.out.println("------乘法------");
BigDecimalf=d1.multiply(d2); // 0.02System.out.println(f);
System.out.println("------除法------");
BigDecimalg=d1.divide(d2); // 0.5System.out.println(g);
System.out.println("------");
// 注:BigDecimal一定是精确运算,否则报错BigDecimala1=BigDecimal.valueOf(10.0);
BigDecimalb1=BigDecimal.valueOf(3.0);
//        BigDecimal c1 = a1.divide(b1);//        System.out.println(c1); // 报错,值是3.333333333...  无法精确计算/*  调用divide()的重载方法进行精度保留计算divide(BigDecimal divisor, int scale, RoundingMode roundingMode)参数一:除数参数二:保留几位小数参数三:舍入模式*/BigDecimalc1=a1.divide(b1, 2, RoundingMode.HALF_UP);
System.out.println(c1); // 3.33 保留两位小数,第三位小数四舍五入System.out.println("------");
// 在运算结束后,需要转成double基本类型,进行下一步的业务(BigDecimal是手段,double是目的)doublers=d.doubleValue();
System.out.println(rs); // 0.3 double类型    }
}
相关文章
|
14天前
|
搜索推荐 Java
Java的面向对象特性主要包括封装、继承和多态
【4月更文挑战第5天】Java的面向对象特性主要包括封装、继承和多态
13 3
|
13天前
|
缓存 安全 Java
Java并发编程进阶:深入理解Java内存模型
【4月更文挑战第6天】Java内存模型(JMM)是多线程编程的关键,定义了线程间共享变量读写的规则,确保数据一致性和可见性。主要包括原子性、可见性和有序性三大特性。Happens-Before原则规定操作顺序,内存屏障和锁则保障这些原则的实施。理解JMM和相关机制对于编写线程安全、高性能的Java并发程序至关重要。
|
22小时前
|
安全 Java API
java借助代理ip,解决访问api频繁导致ip被禁的问题
java借助代理ip,解决访问api频繁导致ip被禁的问题
|
3天前
|
存储 Java
Java基础教程(7)-Java中的面向对象和类
【4月更文挑战第7天】Java是面向对象编程(OOP)语言,强调将事务抽象成对象。面向对象与面向过程的区别在于,前者通过对象间的交互解决问题,后者按步骤顺序执行。类是对象的模板,对象是类的实例。创建类使用`class`关键字,对象通过`new`运算符动态分配内存。方法包括构造函数和一般方法,构造函数用于对象初始化,一般方法处理逻辑。方法可以有0个或多个参数,可变参数用`类型...`定义。`this`关键字用于访问当前对象的属性。
|
3天前
|
存储 安全 Java
说说Java 8 引入的Stream API
说说Java 8 引入的Stream API
7 0
|
3天前
|
分布式计算 Java API
Java 8新特性之Lambda表达式与Stream API
【4月更文挑战第16天】本文将介绍Java 8中的两个重要新特性:Lambda表达式和Stream API。Lambda表达式是Java 8中引入的一种新的编程语法,它允许我们将函数作为参数传递给其他方法,从而使代码更加简洁、易读。Stream API是Java 8中引入的一种新的数据处理方式,它允许我们以声明式的方式处理数据,从而使代码更加简洁、高效。本文将通过实例代码详细讲解这两个新特性的使用方法和优势。
|
4天前
|
安全 Java API
RESTful API设计与实现:Java后台开发指南
【4月更文挑战第15天】本文介绍了如何使用Java开发RESTful API,重点是Spring Boot框架和Spring MVC。遵循无状态、统一接口、资源标识和JSON数据格式的设计原则,通过创建控制器处理HTTP请求,如示例中的用户管理操作。此外,文章还提及数据绑定、验证、异常处理和跨域支持。最后,提出了版本控制、安全性、文档测试以及限流和缓存的最佳实践,以确保API的稳定、安全和高效。
|
7天前
|
安全 Java 编译器
接口之美,内部之妙:深入解析Java的接口与内部类
接口之美,内部之妙:深入解析Java的接口与内部类
25 0
接口之美,内部之妙:深入解析Java的接口与内部类
|
7天前
|
存储 Java 编译器
对象的交响曲:深入理解Java面向对象的绝妙之处
对象的交响曲:深入理解Java面向对象的绝妙之处
36 0
对象的交响曲:深入理解Java面向对象的绝妙之处
|
7天前
|
存储 Java 关系型数据库
掌握Java 8 Stream API的艺术:详解流式编程(一)
掌握Java 8 Stream API的艺术:详解流式编程
35 1