一、内部类
(一)概述
1、概述:定义在类的内部的类,和方法、变量等,均作为类的成员
2、根据定义位置的不同,分为:
(1)成员内部类
(2)局部内部类
3、成员内部类:
(1)普通成员内部类
(2)私有成员内部类
(3)静态成员内部类
4、根据表示方式的不同:
(1)有名字的内部类
(2)匿名内部类
(二)普通成员内部类
1、定义在类成员位置的类,就是成员内部类
2、格式:
class 外部类类名 {
外部类成员;
class 内部类类名 {
内部类成员;
}
}
public class Demo01_InnerClass {
public static void main(String[] args) {
//Heart01 h = new Heart01();
//间接访问 创建外部类对象,外部类对象调用外部类方法,外部类方法访问内部类
Body01 b = new Body01();
b.test();
//直接访问
Body01.Heart01 hb = new Body01().new Heart01();
System.out.println(hb.name);
}
}
/**
* 外部类
* 1、内部类访问外部类
* 2、外部类访问内部类
* 3、外部类以外访问内部类
*/
class Body01 {
String name = "外部类成员变量";
public void test() {
System.out.println("外部类的方法执行了");
Heart01 h = new Heart01();
//外部类可以访问内部类成员变量
System.out.println(h.name);
//外部类可以访问内部类成员方法
h.show();
}
//内部类
class Heart01 {
String name = "内部类成员变量";
public void show() {
//内部类可以访问外部类成员变量
System.out.println(name);
//内部类可以访问外部类成员方法
//test();
System.out.println("nei部类的方法执行了");
}
}
}
(三)私有成员内部类
1、在普通成员内部类的声明上加上
private
关键字
2、格式:
class 外部类类名 {
外部类成员;
private class 内部类类名 {
内部类成员;
}
}
public class Demo01_InnerClass {
public static void main(String[] args) {
//Heart01 h = new Heart01();
//间接访问 创建外部类对象,外部类对象调用外部类方法,外部类方法访问内部类
Body01 b = new Body01();
b.test();
//私有内部类不能直接访问
/*Body01.Heart01 hb = new Body01().new Heart01();
System.out.println(hb.name);*/
}
}
/**
* 外部类
* 1、内部类访问外部类
* 2、外部类访问内部类
* 3、外部类以外访问内部类
*/
class Body01 {
String name = "外部类成员变量";
public void test() {
System.out.println("外部类的方法执行了");
Heart01 h = new Heart01();
//外部类可以访问内部类成员变量
System.out.println(h.name);
//外部类可以访问内部类成员方法
h.show();
}
//内部类
private class Heart01 {
String name = "内部类成员变量";
public void show() {
//内部类可以访问外部类成员变量
System.out.println(name);
//内部类可以访问外部类成员方法
//test();
System.out.println("nei部类的方法执行了");
}
}
}
(四)静态成员内部类
1、格式
class 外部类类名 {
外部类成员;
static class 内部类类名 {
内部类成员;
}
}
public class Demo02_Static {
public static void main(String[] args) {
Body02 b = new Body02();
b.test1();
b.test2();
//静态内部类可以直接访问
Body02.Heart02 hb = new Body02.Heart02();
System.out.println(hb.name);
System.out.println(hb.str);
hb.test01();
hb.test02();
}
}
/**
* 只要遵循:静态不能访问非静态,非静态可以访问静态,静态可以访问静态
*/
class Body02 {
String name = "非静态成员变量";
static String str = "静态成员变量";
public void test1() {
Heart02 h = new Heart02();
System.out.println(h.name + h.str);
h.test01();
h.test02();
System.out.println("非静态成员方法执行了");
}
public static void test2() {
Heart02 h = new Heart02();
System.out.println(h.name + h.str);
h.test01();
h.test02();
System.out.println("静态成员方法执行了");
}
//内部类
static class Heart02 {
String name = "neiBuLei非静态成员变量";
static String str = "neiBuLei静态成员变量";
public void test01() {
//System.out.println(name);
System.out.println(str);
//test1();
test2();
System.out.println("neiBuLei非静态成员方法执行了");
}
public static void test02() {
//System.out.println(name);
System.out.println(str);
//test1();
test2();
System.out.println("neiBuLei静态成员方法执行了");
}
}
}
(五)局部内部类
1、概述:定义在方法中的类
2、访问说明
(1)方法中的局部变量在方法外不能被访问,局部内部类与局部变量同作为方法的成员,在方法之外不能访问,所以局部内部类在方法以外没有任何访问方式,并且必须先定义后调用;类似局部变量的先赋值后调用
(2)解决方式:只能执行局部内部类所在的方法,在方法中创建局部内部类的对象,对调用其中的内容进行执行
public class Demo03_InnerMethod {
public static void main(String[] args) {
new Body03().show();
}
}
class Body03 {
String name = "外部类成员变量";
public void test() {
// 外部类不能直接访问局部内部类内容
// Heart03 h = new Heart03();
System.out.println("外部类成员方法");
}
public void show() {
String name = "方法中的局部变量";
//局部内部类
class Heart03 {
String name = "juBu局部内部类成员变量";
public void demo() {
//局部内部类可以访问自己的成员变量、局部内部类所在方法的局部变量,外部类的成员变量
System.out.println(name);
//局部内部类可以访问局部内部类所在的方法,外部类的成员方法
//show();
test();
System.out.println("juBu局部内部类成员方法");
}
}
//局部内部类只能在局部内部类所在的方法中进行访问,并且必须在局部内部类定义之后进行访问
Heart03 h = new Heart03();
System.out.println(h.name);
h.demo();
}
}
(六)匿名内部类
1、概述:没有名字的内部类
2、使用场景
(1)实现抽象类
(2)实现接口
3、格式
new 抽象类类名或者接口名() {
要实现的抽象方法;
};
4、本质:
(1)匿名内部类本质上是一个实现类对象
(2)编译之后也会生成一个
.class
文件
public class Demo04_NoNameClassAndInter {
public static void main(String[] args) {
//第一种写法
//父类引用指向子类对象:多态成员方法访问编译看左边,运行看后边
//MyClass mc = new MyClass() {@Override public void test() {
System.out.println("test方法执行了"); }};
MyClass mc = new MyClass() {
@Override
public void test() {
System.out.println("test方法执行了");
}
};
mc.test();
//接口的声明引用指向子实现类对象
MyInter mi = new MyInter() {
@Override
public void show() {
System.out.println("show方法执行了");
}
};
mi.show();
//第二种写法
new MyClass() {
@Override
public void test() {
System.out.println("test000方法执行了");
}
}.test();
new MyInter() {
@Override
public void show() {
System.out.println("show0000方法执行了");
}
}.show();
}
}
abstract class MyClass {
public abstract void test();
}
interface MyInter {
public abstract void show();
}
二、Object
(一)概述
1、
Object
是所有类层次结构的根类,是所有类的直接或者间接父类
2、随意定义一个类型,不显示继承哪个类,就默认继承
Object
类
(二)常用方法
1、
getClass
()
:获取当前对象所属的类型
2、
hashCode
()
:根据对象的情况,计算对象的哈希码值
3、
toString
()
:重写后:返回对象的字符串表示形式
4、
finalize
()
:当垃圾回收器确定后面该对象不再被使用的时候,就有该对象的垃圾回收器调用此方法,清理空间(对象)
public class Demo05_Methods {
public static void main(String[] args) {
Person p1 = new Person("张三", 23);
//class com.hqyj.demos.Person:获取当前对象所属类型
System.out.println(p1.getClass());
//460141958:根据对象的情况,计算对象的哈希码值
System.out.println(p1.hashCode());
//重写前:com.hqyj.demos.Person@1b6d3586
//重写后:Person{name='张三', age=23}
System.out.println(p1.toString());
}
}
class Person {
String name;
int age;
//alt + insert + toString()
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
(三)equals方法
1、用于比较两个对象是否相等,这两个对象为调用者对象和参数对象
2、在
Object
类型中,比较的是两个对象的地址值是否相等
3、在所属类型中重写
equals
方法之后,比较的是地址值
import java.util.Objects;
public class Demo06_Equals {
public static void main(String[] args) {
Student stu1 = new Student("张三", 23);
Student stu2 = new Student("张三", 23);
System.out.println(stu1.equals(stu2));
}
}
class Student {
private String name;
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
}';
}
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
(四)==和equals的区别
1、共同点:都是用于比较数据是否相等的方式
2、不同点:
(1)==:是一个运算符;
equals
:是一个方法
(2)
==
:可以比较基本数据类型,也可以比较引用数据类型;
equals
:只能比较引用数据类型
(3)
==
:比较基本数据类型比较属性值,比较引用数据类型比较地址值;
equals
:重写前比较地址值,重写后比较属性值
三、StringBuilder
(一)概述
1、
StringBuilder
是一个可变字符序列,因为在类中提供了对应修改的方法
2、
StringBuilder
底层是数组,封装了对底层操作的方法
(二)构造方法
1、
StringBuilder
()
:创建一个字符串生成器,初始容量为
16
2、
StringBuilder
(int capacity)
:创建一个字符串生成器,初始容量为参数指定
3、
StringBuilder
(String str)
:创建一个字符串生成器,初始容量为
16+str
的长度
4、
capacity
()
:返回字符串生成器的容量
5、
length
()
:返回字符串缓冲区中字符的个数
public class Demo07_StringBuilder {
public static void main(String[] args) {
//初始容量为16
StringBuilder sb = new StringBuilder();
System.out.println(sb.capacity());
System.out.println(sb.length());
StringBuilder sb1 = new StringBuilder(10);
System.out.println(sb1.capacity());
System.out.println(sb1.length());
StringBuilder sb2 = new StringBuilder("abc");
System.out.println(sb2.capacity());
System.out.println(sb2.length());
}
}
(三)添加功能
1、
append
(int i)
:将任意类型的参数追加到当前课表字符序列之后
2、底层操作:当字符串个数和当前数组容积进行比较,如果溢出,就做数组的拷贝,将原有数组的内容添加到新的数组中,其中,新数组的容积为【原来容积<< 1 + 2
】
3、
insert
(int offset, int i)
:任意数据类型插入到指定位置
public class Demo08_Append {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
System.out.println(sb.capacity());
for (int i = 1; i <= 71; i++) {
//sb.append("1");
sb.insert(0, "1");
}
//16 34 70 142 286 [<< 1 + 2]
System.out.println(sb.capacity());
}
}
(四)比较+拼接和Stringbuilder
public class Demo09_Question {
public static void main(String[] args) {
//+拼接 StringBuilder StringBuffer
//testString();
testStringBuilder();
testStringBuffer();
}
public static void testStringBuffer() {
StringBuffer sb = new StringBuffer("");
long start = System.currentTimeMillis();
for (long i = 0; i < 70000000; i++) {
sb.append(i);
}
long end = System.currentTimeMillis();
System.out.println("StringBuffer:" + (end - start));
}
private static void testStringBuilder() {
StringBuilder sb = new StringBuilder("");
long start = System.currentTimeMillis();
for (long i = 0; i < 70000000; i++) {
sb.append(i);
}
long end = System.currentTimeMillis();
System.out.println("StringBuilder:" + (end - start));
}
private static void testString() {
String str = "";
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
str += i;
}
long end = System.currentTimeMillis();
System.out.println("String:" + (end - start));
}
}
(五)StringBuilder和StringBuffer
1、共同点:都是可变字符序列,都是字符串生成器,都是字符串缓冲区
2、不同点:
(1)线程安全性不同
StringBuilder:安全性低
StringBuffer:安全性高
(2)效率不同:
StringBuilder:效率高
StringBuffer:效率低
(3)版本
StringBuilder:
JDK1.5
StringBuffer:
JDK1.0