package chapter04;
import java.math.BigDecimal;
public class Demo04 {
public static void main(String[] args) {
double b1=1.0;
double b2=0.9;
System.out.println(b1-b2);
//使用BigDecimal类
BigDecimal bg1=new BigDecimal("1.0");//创建一个BigDecimal的对象,为保证数值精度,传入字符串最保险,
BigDecimal bg2=new BigDecimal("0.9");
BigDecimal r1=bg1.subtract(bg2);//创建了的对象不能在使用加减乘除等运算符,需要使用方法
System.out.println(r1);
}
}
内部类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uBKnB4QB-1614608311239)(D:\图片\未命名文件.png)]
成员内部类
public class Body {
class head{
}
}
概念:在一个类的内部再定义一个完整的类,被定义的类作为外部类成员使用
特点:
-
内部类编译之后会生成独立的字节码
-
内部类可以直接访问外部内的私有成员
-
可为外部类提供必要的内部功能组件
-
在类的内部类定义,与实例变量,实列方法同级别
-
实例内部类时,必须依赖外部类
public class Application { public static void main(String[] args) { Body body=new Body(); Body.Head head=body.new Head(); head.show(); } }
或
public class Application { public static void main(String[] args) { //Body body=new Body(); //Body.Head head=body.new Head(); //head.show(); Body.Head head=new Body().new Head(); head.show(); } }
-
当外部类和内部类存在属性重名时,会优先访问内部类属性
列:
public class Body { private String name="张三"; private int age=12; class Head{ private String address="武汉"; private String name="李四"; public void show(){ System.out.println(name); System.out.println(age); System.out.println(address); } } }
若想访问外部属性需要添加前缀、
public class Body { private String name="张三"; private int age=12; class Head{ private String address="武汉"; private String name="李四"; public void show(){ System.out.println(Body.this.name); System.out.println(age); System.out.println(address); } } }
-
成员内部类不能定义静态量,最多只能定义静态常量
private static final String country="中国";
静态内部类
静态内部类使用static修饰,虽然在外部类里面定义,但与外部类同级别,也就是说该类与外部类无依赖关系。
如
public class Demofather {
private String name="张三";
private int age=21;
static class Demoson{
private String country="中国";
private int tall=156;
//静态成员
private static int phone=11111;
public void show(){
//调用外部类的私有属性必须先将外部类实列化
Demofather demofather=new Demofather();
System.out.println(demofather.name);
System.out.println(demofather.age);
//调用静态类的私有属性
System.out.println(country);
System.out.println(tall);
System.out.println(Demoson.phone);
}
}
}
public class Application {
public static void main(String[] args) {
//Body body=new Body();
//Body.Head head=body.new Head();
//head.show();
Body.Head head=new Body().new Head();
head.show();
Demofather.Demoson demoson=new Demofather.Demoson();//此处Demofather后面没有加括号,表示此处实列化的类是Demoson,
//Demofather表示Demoson是在Demofather里面的类
demoson.show();
}
}
注:只有静态内部类才能使用static修饰,期刊他的类不能使用static修饰。
局部内部类
-
定义在外部类的方法中,作用范围和创建对象范围仅限于当前方法
-
局部内部类访问外部类当前方法中的局部变量时,因为无法保障变量的生命周期与自身相同,变量必须修饰为final。
-
限制类的使用范围
-
方法里面的变量不能使用private等修饰
package chapter01; public class Outer { //局部内部类 private String name="闻峰"; private int age=25; public void show(){ String name="女朋友"; int age1=24; class Inner{ private String address="罗田"; public void display(){ System.out.println(Outer.this.name); System.out.println(Outer.this.age); System.out.println("有一个"+name); System.out.println(age1); //此处访问存放局部内部类方法的私有属性 //此处的属性必须是常量 //JDK1.7时,要在属性前加final,JDK1.8后默认加了final //因此此处不需要加final System.out.println(address); } } Inner inner=new Inner(); inner.display(); } }
使用局部内部类实现接口
package chapter02; //接口 public interface Usb { void service(); }
package chapter02; public class TestRun { public static void main(String[] args) { /* RunUsb runUsb=new RunUsb(); runUsb.service(); */ //局部内部类实现接口 class Fan implements Usb{ @Override public void service(){ System.out.println("USB连接成功,风扇开始工作了......"); } } Fan fan=new Fan(); fan.service(); } }
匿名内部类
package chapter02; import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer; public class TestRun { public static void main(String[] args) { /* RunUsb runUsb=new RunUsb(); runUsb.service(); */ //局部内部类实现接口 /*class Fan implements Usb{ @Override public void service(){ System.out.println("USB连接成功,风扇开始工作了......"); } } Fan fan=new Fan(); fan.service(); */ //创建匿名内部类 Usb usb=new Usb() { @Override public void service() { System.out.println("我有一个女朋友"); } };//注意此处要加分号 usb.service(); } }
- 没有类名的局部内部类(一切特征都与局部内部类相同)
- 必须继承一个父类或者实现一个接口
- 定义类,实现类,创建对象的语法合并,只能创一个该类的对象
- 优点:减少代码量
- 缺点:可读性较差
Object类
概念:超类,基类,所有类的直接或间接父类,位于继承树的最顶端
特点:
-
任何类,如果没有书写extends显示继承某个类,都默认直接继承Object类
-
Object类中所定义的方法,时所有对象都具备的方法
-
Object可以存储的任何对象
(1)作为参数可以接受任何对象
(2)作为返回值,可以返回任何对象
(getClass()方法)
一般用于判断两个对象的类型是否相同
package chapter03;
public class Student {
private String name;
private int age;
//构造器
public Student(String name,int age){
super();
this.name=name;
this.age=age;
}
//get/set
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
}
package chapter03;
public class TestStuden {
public static void main(String[] args) {
Student s1=new Student("紫陌",22);
Student s2=new Student("子君",23);
//判断S1和S2是不是同一个类型
Class class1=s1.getClass();
Class class2=s2.getClass();
if(class1==class2){
System.out.println("S1和S2属于同一个类型");
}else{
System.out.println("S1和S2不属于同一个类型");
}
}
}
hashCode()方法
作用:返回该对象的哈希码值
哈希值:根据对象的地址或字符串或数字使用hash算法计算出来的int类型的数值
public int hashCode(){}
一般情况下相同对象返回相同哈希码
package chapter03;
public class TestStuden {
public static void main(String[] args) {
Student s1=new Student("紫陌",22);
Student s2=new Student("子君",23);
//判断S1和S2是不是同一个类型
Class class1=s1.getClass();
Class class2=s2.getClass();
if(class1==class2){
System.out.println("S1和S2属于同一个类型");
}else{
System.out.println("S1和S2不属于同一个类型");
}
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
Student s3=s2;
System.out.println(s3.hashCode());
}
}
结果:
S1和S2属于同一个类型
460141958
1163157884
1163157884
toString方法
public String toString(){};
该方法返回对象的类型与哈希值的字符串
如
package chapter03;
public class TestStuden {
public static void main(String[] args) {
Student s1=new Student("紫陌",22);
Student s2=new Student("子君",23);
//判断S1和S2是不是同一个类型
Class class1=s1.getClass();
Class class2=s2.getClass();
if(class1==class2){
System.out.println("S1和S2属于同一个类型");
}else{
System.out.println("S1和S2不属于同一个类型");
}
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
Student s3=s2;
System.out.println(s3.hashCode());
System.out.println("---------------------toString--------------------");
//toString
System.out.println(s1.toString());
System.out.println(s2.toString());
}
}
结果
chapter03.Student@1b6d3586
chapter03.Student@4554617c
重写toString方法可返回其他值
如
package chapter03;
public class Student {
private String name;
private int age;
//构造器
public Student(String name,int age){
super();
this.name=name;
this.age=age;
}
//get/set
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
//重写toString方法
@Override
public String toString(){
return name+": "+age;
}
}
结果
---------------------toString--------------------
紫陌: 22
子君: 23
equals方法
public boolean equals(obj s){}
比较两个对象的地址是否相同,相同返回false,不同返回true
finalize方法
作用:当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象
垃圾对象:没有有效引用指向此对象时,为垃圾对象
垃圾回收:由GC销毁垃圾对象,释放数据存储空间
自动回收机制:JVM内存耗尽,一次性回收所有垃圾对象
手动回收机制:使用System.gc():通知JVM执行垃圾回收
//重写finalize方法
@Override
protected void finalize() throws Throwable{
System.out.println(this.name+"对象被回收了");
}
package chapter03;
public class TestStudent2 {
public static void main(String[] args) {
new Student("紫陌",22);
new Student("子沫",23);
System.gc();
System.out.println("回收垃圾");
}
}
基本数据类型都存储在栈中,
包装类
概念:基本数据类型所对应的引用数据类型
一般来说基本数据类型都存储在栈里面,引用数据类型存储在堆里面,栈里面存储的是对象的地址。
由于基本数据类型的使用只能是逻辑运算符,调用方法太单一,所以为了提高基本数据类型的功能,所以分别对八种基本数据类型重新设计了引用数据类型,也就是包装类,此时基本数据类型也就拥有了属性和方法。包装类的默认值是null。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sxdBbm3B-1614608311241)(C:\Users\Administrator.DESKTOP-F6IAFVV\AppData\Roaming\Typora\typora-user-images\image-20210228140351185.png)]
装箱与拆箱
前提:基本数据类型和基本数据类型的数据存储在栈中,引用数据类型和引用数据存储在堆中。
装箱:将进本数据类型的数据装到堆中,设置为包装类
基本类型------->引用类型
拆箱:将引用数据类型的数据从堆中放到栈中
引用类型------->基本类型
package chapter03;
public class TestOut {
public static void main(String[] args) {
//JDK1.5以及之前的装箱拆箱方法
int num1=10;
//装箱:
//方法1
Integer integer1=new Integer(num1);
//方法2
Integer integer2=Integer.valueOf(num1);
//拆箱:
Integer integer3=new Integer(100);
int num2=integer3.intValue();
//JDK1.5以后提供了自动装箱和自动拆箱的功能
int age1=12;
Integer integer=age1;
int age2=integer;
}
}
字符串与基本类型之间的转换
//基本类型转换为字符串
//方法1:使用+号
int n=100;
String s1=n+"";
//方法2:使用integer中的方法
String s2=Integer.toString(n);
System.out.println(s1);
System.out.println(s2);
//字符串转换为基本类型
String string="150";
int num5=Integer.parseInt(string);
System.out.println(num5);
//boolean字符串转基本类型,“true”>>>>true,非“true”>>>>false
String str2="true";
boolean b1=Boolean.parseBoolean(str2);
System.out.println(b1);
- 八种包装类型提供不同类型间的转换方式
- 注意要保证类型兼容,否则会抛出异常,比如将字符串“150aa”转换为int类型。
缓冲区
1:使用Integer装箱时,两个装箱值相同的对象并不相同,因为地址不同
如
package chapter03;
public class TestDemo01 {
public static void main(String[] args) {
Integer integer1=new Integer(100);
Integer integer2=new Integer(100);
System.out.println(integer1==integer2);
}
}
结果
false
2:使用Integer.valueOf装箱因为该方法内部有256大小的缓冲区,因此,装-128–127范围内的数时,返回的地址一样,所以为true
如
package chapter03;
public class TestDemo01 {
public static void main(String[] args) {
Integer integer1=new Integer(100);
Integer integer2=new Integer(100);
System.out.println(integer1==integer2);
//使用Integer.valueOf装箱
Integer integer3=Integer.valueOf(100);
Integer integer4=Integer.valueOf(100);
System.out.println(integer3==integer4);
}
}
结果:
true
结果溢出
package chapter03;
public class TestDemo01 {
public static void main(String[] args) {
Integer integer1=new Integer(100);
Integer integer2=new Integer(100);
System.out.println(integer1==integer2);
//使用Integer.valueOf装箱
Integer integer3=Integer.valueOf(100);
Integer integer4=Integer.valueOf(100);
System.out.println(integer3==integer4);
//溢出
Integer integer5=Integer.valueOf(200);
Integer integer6=Integer.valueOf(200);
System.out.println(integer5==integer6);
}
}
结果:
false
注:一般自动装箱默认使用Integer.valueOf方法
String类
字符串存放的地方
常量池:存放字符串的地方,里面的字符串不重复
(1)情况1 ,定义一个name的字符串存放“紫陌”
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wtrY4k5O-1614608311242)(C:\Users\Administrator.DESKTOP-F6IAFVV\AppData\Roaming\Typora\typora-user-images\image-20210228212906229.png)]
package chapter04;
public class TestOut {
public static void main(String[] args) {
String name="紫陌";
}
}
(2)给name重新赋值为“子君”,此时在常量池中在常量池中搜索是否有“子君”字符串,若没有,则重新创建一个“子君”字符串,原先已经创建了的“紫陌”字符串不动,所以说字符串一旦创建便便不可更改,只需让name指向“子君”字符串,存放“子君”字符串的地址。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xrRJWOJU-1614608311243)(C:\Users\Administrator.DESKTOP-F6IAFVV\AppData\Roaming\Typora\typora-user-images\image-20210228215023508.png)]
package chapter04;
public class TestOut {
public static void main(String[] args) {
String name="紫陌";
name="子君";//重新给,name赋值
}
}
(3)情况三
当使用String类来创建字符串时,JVM会同时在堆和常量池中创建两个对象,且name中存放的是堆中字符串的地址,但在实际运行中堆里面其实并没有该字符串实体,而是使用常量池中创建的字符串。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fBTDXBCt-1614608311244)(C:\Users\Administrator.DESKTOP-F6IAFVV\AppData\Roaming\Typora\typora-user-images\image-20210228220143185.png)]
package chapter04;
public class TestOut {
public static void main(String[] args) {
String name="紫陌";
name="子君";//重新给,name赋值
//使用String类创建字符串
String str1=new String("java");
}
}
拓展:当使用String方法方法创建两个内容相同的字符串时,两个变量的存放的变量并不相同,如
String str1=new String("java");
String str2=new String("java");
System.out.println(str1==str2);
结果:
false
原因是在使用String时在堆中又创建了一个新的对象,该地址与原先的地址不同
如图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2iXEhdAA-1614608311244)(C:\Users\Administrator.DESKTOP-F6IAFVV\AppData\Roaming\Typora\typora-user-images\image-20210228221118987.png)]
但他们的值相同,也就是说使用equals方法比较,返回的结果、是true,如下
String str1=new String("java");
String str2=new String("java");
System.out.println(str1==str2);
System.out.println(str1.equals(str2));
结果:
true
String 常用的的方法
-
length()获取字符串的长度
-
charAt(int index)返回某个位置的字符
-
contains(String str)判断是否包含了某个子字符串
package chapter04; public class Demo01 { public static void main(String[] args) { String str="我会找到一个女朋友"; System.out.println(str.length()); System.out.println(str.charAt(1)); System.out.println(str.contains("女")); } } 结果: 9 会 true
-
toCharArray();返回字符串对应的数组
-
indexOf();返回子字符串首次出现的位置
-
lastIndexOf();返回子字符串最后一次出现的位置
StringBuffer类
StringBuffer与String类的作用相同,都是创建字符串的,但StringBuffer比String更快,占用的内存空间更少。
java四种主要方法
package chapter04;
//StringBuffer
public class Demo02 {
public static void main(String[] args) {
StringBuffer str = new StringBuffer();
//append 追加
str.append("java世界第一");
System.out.println(str.toString());
//insert 插入
str.insert(0,"hello");
System.out.println(str.toString());
//repalce 替换
str.replace(0,5,"我说");//第一个索引为起始位置,第二个索引为截至位置,但不包含截至位置
System.out.println(str.toString());
//delete 删除
str.delete(0,2);
System.out.println(str.toString());
}
}
StringBuffer比Stringbuilder效率低,但线程更安全
时间比较
package chapter04;
public class Demo03 {
public static void main(String[] args) {
//String用时
//获取初始时间
long start=System.currentTimeMillis();
String str="";
for(int i=0;i<99999;i++){
str+=i;
}
long end=System.currentTimeMillis();
System.out.println("用时:"+(end-start));
//SteingBuffer用时
long start1=System.currentTimeMillis();
StringBuffer str1=new StringBuffer();
for(int j=0;j<99999;j++){
str1.append(j);
}
long end1=System.currentTimeMillis();
System.out.println("用时:"+(end1-start1));
//StringBuilder用时
long start2=System.currentTimeMillis();
StringBuilder str2=new StringBuilder();
for(int k=0;k<99999;k++){
str2.append(k);
}
long end2=System.currentTimeMillis();
System.out.println("用时:"+(end2-start2));
}
}
结果
用时:23920
用时:3
用时:2
BigDecimal类
作用:应用于浮点数的精确运算
前提:由于java里面浮点数的存储并不是精确的存储,比如0.9在内存中存储的可能是0.89999999999…等,所以当我们要使用浮点数做精确运算时,,需要用到BigDecimal类。
如:
package chapter04;
public class Demo04 {
public static void main(String[] args) {
double b1=1.0;
double b2=0.9;
System.out.println(b1-b2);
}
}
结果
0.09999999999999998
显然以上代码的结果有误
使用BigDecimal类运算
package chapter04;
import java.math.BigDecimal;
public class Demo04 {
public static void main(String[] args) {
double b1=1.0;
double b2=0.9;
System.out.println(b1-b2);
//使用BigDecimal类
BigDecimal bg1=new BigDecimal("1.0");//创建一个BigDecimal的对象,为保证数值精度,传入字符串最保险,
BigDecimal bg2=new BigDecimal("0.9");
BigDecimal r1=bg1.subtract(bg2);//创建了的对象不能在使用加减乘除等运算符,需要使用方法
System.out.println(r1);
}
}
结果
0.1
BigDecimal里面的常用方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7hkfEo9k-1614608311245)(C:\Users\Administrator.DESKTOP-F6IAFVV\AppData\Roaming\Typora\typora-user-images\image-20210301205032833.png)]
当运算数字除不尽时,需要填写保留的小数位数和,取数的模式,如图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yrcFMfyc-1614608311245)(C:\Users\Administrator.DESKTOP-F6IAFVV\AppData\Roaming\Typora\typora-user-images\image-20210301205224636.png)]
否则会报错
Data类
过时了,大部分方法被Calendar类的方法所取代
Calendar类
package chapter04;
import java.util.Calendar;
public class Demo05 {
public static void main(String[] args) {
//由于Calendar类使用了protect修饰,因此不能直接new一个对象,只能通过其内部的getInstance()静态方法来创建对象
Calendar calendar= Calendar.getInstance();
System.out.println(calendar.getTime());
System.out.println(calendar.getTime().toLocaleString());
System.out.println(calendar.getTimeInMillis());
//获取时间信息
int year=calendar.get(Calendar.YEAR);
int month=calendar.get(Calendar.MONTH);//这里的月是从0开始的到11
int day=calendar.get(Calendar.DAY_OF_MONTH);
int hour=calendar.get(Calendar.HOUR_OF_DAY);
int minute=calendar.get(Calendar.MINUTE);
int second=calendar.get(Calendar.SECOND);
System.out.println(year+"年"+(month+1)+"月"+day+"日"+hour+"时"+minute+"分"+second+"秒");
}
}
SimpleDataFormat类
作用:将日期转换为字符串,或将字符串转换为日期,也就是解析
如下,按要求格式返回时间
package chapter04;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo06 {
public static void main(String[] args) {
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
Date date=new Date();
System.out.println(date);
String str=simpleDateFormat.format(date);
System.out.println(str);
}
}
结果
Mon Mar 01 21:47:02 CST 2021
2021年03月01日21:47:02
解析
package chapter04;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo06 {
public static void main(String[] args) throws Exception{
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy/MM/dd");
Date date=new Date();
System.out.println(date);
String str=simpleDateFormat.format(date);
System.out.println(str);
//解析
Date std=simpleDateFormat.parse("1996/09/19");
System.out.println(std);
}
}
System类
作用:主要用于获取系统的属性数据和其他操作,构造方法私有的。