- 成员内部类
- 局部内部类
- 匿名内部类
内部类的概念
特点:
-
编译之后会生成独立的字节码文件
-
内部类可直接访问外部类的私有成员,而不破坏封装
-
可为外部类提供必要的内部功能组件
内部类是否会再次生成class文件?
答案是的
例如我自己写了一个匿名内部类
class生成目录下找到了
成员内部类
//成员内部类
public class Outer {
//实例变量
private String name = "张三";
private int age = 23;
//内部类
class Inner{
private String address = "hangzhou";
private String phone = "120";
//方法
public void show(){
//外部类
System.out.println(name);
System.out.println(age);
//内部类
System.out.println(address);
System.out.println(phone);
}
}
}
public class Test {
public static void main(String[] args) {
//创建外部类对象
Outer outer = new Outer();
//创建内部类对象
Outer.Inner inner = outer.new Inner();
//嫌麻烦可以换成这样
Outer.Inner inner = new Outer().new Inner();
inner.show();
}
}
//成员内部类
public class Outer {
//实例变量
private String name = "张三";
//内部类
class Inner{
private String name ="李四";
//方法
public void show(){
System.out.println(name);
//如果需要访问内部类对象,改成这样
System.out.println(Outer.this.name);
}
}
}
private static final String country = "中国";
静态内部类
//静态内部类
public class Staticc {
//私有属性
private String name = "XXX";
private int age = 12;
//静态内部类
static class Inner{
//静态内部类中的私有属性
private String address = "hangzhou";
private String phone = "120";
//静态内部类中静态的私有属性
private static final String country = "中国";
public void show(){
Staticc staticc = new Staticc();
System.out.println(staticc.age);
System.out.println(Inner.country);
}
}
}
public class TestSt {
public static void main(String[] args) {
Staticc.Inner inner = new Staticc.Inner();
inner.show();
}
}
public class part {
//实例变量
private String name = "张三";
private int age = 23;
public void show(){
//定义局部变量
final String address="sz";
//局部类-局部内部类前面不能加任何访问修饰符public
//局部变量 本身就是 一个访问权限 的设定啊。 只能在局部调用
//定义在方法中的变量叫局部变量,局部变量的有效范围就是方法内,在局部变量中加上public,或者其他修饰符的话(编译都通不过),就破坏了局部变量的范围,可以说局部变量是为方法而生的。局部变量中的局部就已经说明了范围
class Inner{
private String address = "hangzhou";
private String email = "120";
public void show2(){
//访问外部类属性
System.out.println(part.this.age);
System.out.println(part.this.name);
//访问内部类属性
System.out.println(this.address);
System.out.println(this.email);
//调用局部变量
//在JDK1.7之前,变量必须加上final,JDK1.8后是自动添加的
System.out.println(address);
}
}
Inner inner = new Inner();
inner.show2();
}
}
final String address="sz";
匿名内部类
- 没有类名的局部内部类(一切特征都与局部内部类相同)
- 必须继承一个父类或者实现一个接口
public class TestUsb {
public static void main(String[] args) {
//使用匿名内部类
//定义类、实现类、创建对象的语法合并,只能创建一个该类的对象。
Usb usb = new Usb() {
@Override
public void Service() {
System.out.println("开始旋转");
}
};
usb.Service();
}
}
优点:减少代码量
缺点:可读性太差
public class TestUsb {
public static void main(String[] args) {
//创建接口类型的变量
Usb usb = new Mouse();
usb.Service();
局部内部类
class Fan implements Usb{
@Override
public void Service() {
System.out.println("连接电脑成功!");
}
}
//使用局部内部类开始创建对象
Usb usb = new Fan();
usb.Service();
}
}
public interface Usb {
void Service();
}
public class Mouse implements Usb{
@Override
public void Service() {}
}
Object类
-
作为参数,可以接受任何对象
-
作为返回值,可返回任何对象
getClass()方法
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("li",11);
Student s2 = new Student("wang",23);
//判断S1和S2是否是同意类型
Class class1 = s1.getClass();
Class class2 = s2.getClass();
if (class1==class2){
System.out.println("same");
}else {
System.out.println("no same");
}
}
}
hashCode()方法
package commonclass.getclas;
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student("li",11);
Student s2 = new Student("li",11);
//打印哈希值
System.out.println("====================");
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
//赋值给到新的变量时,哈希值也会被赋值过去
Student s3 = s1;
System.out.println(s3.hashCode());
System.out.println("====================");
}
}
输出
1956725890
356573597
1956725890
====================
思考:equals未重写时,比较的是内容还是内存地址?
equal是object类的方法,所有没有重写这个类的方法;比较的都是内存地址,和==是一样的,重写后该方法是按照重写的方法来进行比较,比如String类就重写了这个方法,比较的是内容。
如何将equals()方法进行覆盖?
-
比较两个引用是否指向同一个对象
-
判断obj是否为null
-
判断两个引用指向的实际对象类型是否一致、
-
强制类型转换
-
依次比较各个属性值是否相同。
@Override
public boolean equals(Object o) {
//1、判断两个对象是否是同一引用
if (this==o){
return true;
}
//2、判断o是否为null
if (o==null){
return false;
}
//3、判断是否是同一类型
//第一种
// if(this.getClass()==o.getClass()){
//
// }
//第二种
if(o instanceof Student){
//4、强制类型转换
Student s=(Student) o;
//5、比较各个属性值是否相同
if (this.name.equals(s.getName())&&this.age==s.getAge()){
return true;
}
}
return false;
}
这是手写的,可能存在bug,可以直接使用idea的快捷键alt+insert自动重写equals
finalize()方法
作用:当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列。
思考:什么样的对象会被判定为垃圾对象?
public class TestStudent2 {
public static void main(String[] args) {
//已经有指定的,无法直接回收
// Student s1 = new Student("a",1);
// Student s2 = new Student("b",1);
//无指定
new Student("c",1);
new Student("d",1);
//垃圾回收
System.gc();
System.out.println("已回收");
}
}
//重写finalize方法
@Override
protected void finalize() throws Throwable {
System.out.println(this.name+"销毁");
}
垃圾对象:没有有效引用指向此对象时,为垃圾对象。
自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
手动回收机制:使用System.gc();通知JVM执行垃圾回收。
什么是包装类?
装箱和拆箱
基本数据类型存储在栈中,引用数据类型是存储在堆中
将堆中的对象放到栈中,就是拆箱
//自动装箱和拆箱
public class Demo01 {
public static void main(String[] args) {
//JDK1.5之前的写法
//装箱操作、基本类型转换引用类型
int num1 = 100;
//使用Integer创建对象,装箱的两种方法
Integer integer1 = new Integer(num1);
Integer integer2 = Integer.valueOf(num1);
System.out.println("装箱");
System.out.println(integer1);
System.out.println(integer2);
//拆箱操作、引用类型转换基本类型
Integer integer3 = new Integer(100);
int num2 = integer3.intValue();
System.out.println(num2);
System.out.println("===================");
//JDK1.5之后的写法
//java提供了自动装箱和拆箱
//自动装箱
int age = 200;
Integer integer4 = age;
System.out.println(integer4);
//自动拆箱
int num3 = integer4;
System.out.println(num3);
}
}
8中包装类提供不同类型间的转换方式:
Number父类提供的6个共性方法
parseXXX()静态方法---将字符串转换成基本类型
valueOf静态方法---装箱操作,基本类型转换成引用类型
注意:需保证类型兼容,否则容易抛出NumberFormatException异常
//字符串与基本类型的转换
//基本类型转换成字符串
int n1 = 20;
//1、使用+
String s1 = n1+"";
//2使用Integer的toString()方法
//radix转换的进制
String s2 = Integer.toString(n1,16);
System.out.println(s1);
System.out.println(s2);
//字符串转换成基本类型
String str = "100";
//使用Integer的parseXXX方法
int n2 = Integer.parseInt(str);
System.out.println(n2);
//boolean字符串转换成基本类型
String str2 = "true";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(str2);
Interger缓冲区
Java预先创建了256个常用的整数包装类型对象;
//关于Integer缓冲区的面试题
public class Demo02 {
public static void main(String[] args) {
//思考?是否相等
//不相等,==比较的是内存地址,
// Integer是引用类型在堆中,所以内存地址不同
Integer integer1 = new Integer(20);
Integer integer2 = new Integer(20);
System.out.println(integer1==integer2);
//思考?是否相等
//相等,相当于自动装箱
//实际完整代码:Integer integer3 = Integer.valueOf(30);
//对于valueOf是有在堆中提前设计的缓存区间,可以存储-128-127之间的数字
Integer integer3 = 30;
Integer integer4 = 30;
System.out.println(integer3==integer4);
//思考?是否相等
//不相等。当范围超出设计的缓存区间,会自动另外开辟新的空间,则为false
Integer integer5 = 300;
Integer integer6 = 300;
System.out.println(integer5==integer6);
}
}
String类
字符串是常量,创建之后不可改变;字符串字面存储在字符串池中,可以共享。
String s1 = "Hello";产生一个对象,字符串池中存储
public class Demo03 {
public static void main(String[] args) {
//注意这里修改的不是s1,而是在常量池中重新开辟了一个空间,叫wang
//s1也指向wang
String s1 = "lee";
s1 = "Wang";
//面试题
//思考:为什么是false?
//new是在堆中开辟新的空间,同时又指向常量池,相当于两个地址
//==比较的是内存地址,所以返回false
String s2 = new String("Zhang");
String s3 = new String("Zhang");
System.out.println(s2==s3);
}
}
常用方法
//String方法
//1、length;返回字符串长度
//2、CharAt;返回某个位置的字符
//3、contain;判断是否包含某个子字符串
String str1 = "王冰冰最美";
System.out.println(str1.length());
System.out.println(str1.charAt(str1.length()-1));
System.out.println(str1.contains("王"));
//4、toCharArray;返回字符串对应的数组
//5、iNdexOf;返回子字符串首次出现的位置
//6、lastIndexOf;返回字符串最后一次出现的位置
System.out.println(Arrays.toString(str1.toCharArray()));
System.out.println(str1.indexOf("冰"));
System.out.println(str1.lastIndexOf("冰"));
//7、trim();去电字符串前面的空格
//8、toUpperCase()/toLowerCase();把小写转换成大写,大写转小写
//9、endWith()/startsWith();是否是以str结尾;或开头
String str2 = " wangbingBingzuimei ";
System.out.println(str2.trim());
System.out.println(str2.toUpperCase());
System.out.println(str2.toLowerCase());
String str3 = "wangbingbing";
System.out.println(str3.endsWith("bing"));
System.out.println(str3.startsWith("wang"));
//10、replace();用新的字符串替换旧的字符或字符串
//11、split();对字符串拆分
String str4 = "[wangbingbing shi ,zui mei de]";
System.out.println(str4.replace("wang","li"));
//加上[] 意味着,可以同时分离空格和逗号(正则表达式)
//+ 意味着出现多个空格和逗号都可以去除
String[] arr = str4.split("[ ,]+");
System.out.println(arr.length);
for (String s:arr
) {
System.out.print(s);
}
//12、补充两个方法equals()、compareTo();
String str5 = "hello";
String str6 = "HELLO";
//equalsIgnoreCase()忽视字母大小进行比较
System.out.println(str5.equalsIgnoreCase(str6));
//compareTo()长度一样,依次比较的是字符
String str7 = "abc";
String str8 = "xyz";
System.out.println(str7.compareTo(str8));
//长度不一样,就比长度
String str9 = "abc";
String str10 = "abcbnm";
System.out.println(str9.compareTo(str10));
StringBuffer和StringBuilder
StringBuffer:可变长字符串,JDK1.0提供,运行效率低,线程安全,用于多线程
/**
* StringBuffer和StringBuilder
* 和String区别
* 1、效率比String更高
* 2、比String更节省内存
*/
public class Demo04 {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
//1、append()、追加
sb.append("wangbingbing");
System.out.println(sb);
sb.append("zuimei");
System.out.println(sb.toString());
//2、insert()、插入
sb.insert(0,"woshuo");
System.out.println(sb.toString());
//3、replace()、替换
sb.replace(0,2,"ni");
System.out.println(sb.toString());
//4、delete()、删除
sb.delete(0,6);
System.out.println(sb.toString());
sb.delete(0,sb.length());
System.out.println(sb.length());
}
}
/**
* 证明StringBuilder效率高于String
*差距是真的大
*/
public class Demo05 {
public static void main(String[] args) {
//开始时间
long start = System.currentTimeMillis();
// String string = "";
// //String的用时
// for (int i = 0; i < 99999; i++) {
// string+=i;
// }
// System.out.println(string);
//StringBuilder的用时
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 99999; i++) {
sb.append(i);
}
System.out.println(sb);
//结束时间
long end = System.currentTimeMillis();
System.out.println("用时"+(end-start));
}
}
输出结果:
StringBuilder:用时19
StringBuffer:用时22036
作用:精确计算浮点数
/**
* BigDecimal的作用
*/
public class Demo06 {
public static void main(String[] args) {
//思考?为什么结果不是准确的
//double是近似值存储,不符合要求,需要借助BigDecimal
double d1 = 1.0;
double d2 = 0.9;
System.out.println(d1-d2);
BigDecimal bd1 = new BigDecimal("1.0");
BigDecimal bd2 = new BigDecimal("0.9");
//减法
BigDecimal r1 = bd1.subtract(bd2);
System.out.println(r1);
//加法
BigDecimal r2 = bd1.add(bd2);
System.out.println(r2);
//乘法
BigDecimal r3 = bd1.multiply(bd2);
System.out.println(r3);
//除法
//1.4-0.5/0.9
BigDecimal r4 = new BigDecimal("1.4")
.subtract(new BigDecimal("0.5"))
.divide(new BigDecimal("0.9"));
System.out.println(r4);
//除法涉及到的近似值
BigDecimal r5 = new BigDecimal("10").divide(new BigDecimal("3"),3,BigDecimal.ROUND_HALF_UP);
System.out.println(r5);
}
}
在计算除法时
除法:.divide(new BigDecimal("3"),scal,RoundingMode mode);
参数
scal:指定小数点精确到小数点后几位
mode:
Date类
-
1秒=1000毫秒
-
1毫秒=1000微秒
-
1微秒=1000纳秒
/**
* Date方法
*
*/
public class Demo07 {
public static void main(String[] args) {
//创建对象
Date date1 = new Date();
//当前时间
System.out.println(date1.toString());
System.out.println(date1.toLocaleString());
//昨天时间
Date date2 = new Date(date1.getTime()-60*60*24*1000);
System.out.println(date2.toLocaleString());
//方法after before
boolean b1 = date1.after(date2);
System.out.println(b1);
boolean b2 = date1.before(date2);
System.out.println(b2);
//比较CompareTo()
int d = date2.compareTo(date1);
System.out.println(d);
//比较是否相等equals()
boolean b3 = date1.equals(date2);
System.out.println(b3);
}
}
Calendar类
作用:Calendar提供了获取或设置各种日历字段的方法
/**
* Calendar类
*/
public class Demo08 {
public static void main(String[] args) {
//因为Calendar修饰符是protected,所以无法new
//1、创建对象
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getTime().toLocaleString());
System.out.println(calendar.getTimeInMillis());
//查看时间
//年
int year = calendar.get(Calendar.YEAR);
//月
int month = calendar.get(Calendar.MONTH);
//日
int day = calendar.get(Calendar.DAY_OF_MONTH);
//HOUR_OF_DAY代表24小时制
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 +
"日" + day +
"时" + hour +
"分" + minute +
"秒" + second);
//3、set方法修改时间
Calendar calendar1 = Calendar.getInstance();
calendar1.set(Calendar.DAY_OF_MONTH,5);
System.out.println(calendar1.getTime().toLocaleString());
//4、add方法修改时间
calendar1.add(Calendar.HOUR_OF_DAY,-1);
System.out.println(calendar1.getTime().toLocaleString());
//5、补充方法,查看参数的最大值
int max = calendar1.getActualMaximum(Calendar.DAY_OF_MONTH);
int min = calendar1.getActualMinimum(Calendar.DAY_OF_MONTH);
System.out.println(max);
System.out.println(min);
}
}
SimpleDateFormat类
进行格式化(日期->文本)、解析(文本->日期)
public class Demo09 {
public static void main(String[] args) throws ParseException {
//1、创建SimpleDateFormat对象
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
//创建Date
Date date = new Date();
//格式化date 把日期转换成字符串
String s1 = simpleDateFormat.format(date);
System.out.println(s1);
//解析,格式要与simpleDateFormat规定的格式相同
Date date1 = simpleDateFormat.parse("2002-02-02 10-11-11");
System.out.println(date1);
}
}
System类
/**
* System类
*/
public class Demo10 {
public static void main(String[] args) {
//1、arraycopy:数组的复制
//src:原数组
//srcPos:从原数组哪个位置开始复制
//dest:目标数组
//destPos:从目标数组的哪个位置开始粘贴
//length:复制的长度
int[] arr1 = {1,2,3,4,56,6};
int[] arr2 = new int[8];
System.arraycopy(arr1,0,arr2,0,6);
for (int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);
}
// Arrays.copyOf();还是使用的System.arraycopy,
//2、复制当前系统时间
long start = System.currentTimeMillis();
for (int i = 0; i < 99999999; i++) {
for (int j = 0; j < 99999999; j++) {
int result = i+j;
}
}
long end = System.currentTimeMillis();
System.out.println("用时:"+(end-start));
//3、建议JVM启动垃圾回收器回收垃圾
System.gc();
//4、退出JVM如果参数为0,正常退出,非0表示异常退出
System.exit(0);
System.out.println("上面喊收工了,后面就不执行了");
}
}