局部内部类定义:
局部内部类是定义在一个方法或者一个作用域里面的类
它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内
将局部内部类看成是局部变量即可
局部内部类的经典使用:
这个块中是我自己对于局部内部类的重新整合学习:
局部内部类的一些特点
* 1,局部内部类处在一个作用域内,出了这个作用域,该内部类就失效了
* 也就是说,仅在方法内部才能够访问该局部内部类
* 这是一种比成员内部类更加极致的封装思想的体现
* 2,我们拿最常见的方法中的局部内部类举例,当你在方法当中需要一个对象来解决一个问题
* 但是不希望外界知道这个对象是如何创建出来,不需要让外界感知到这个类
* 这个时候就需要使用局部内部类
* 如果没有这种需求,就不要滥用它,定义局部内部类很多时候会影响代码结构
* 3,局部内部类什么时候进行类加载?
* 和成员内部类类似,局部内部类想要完成类加载也必须创建它的对象
* 怎么创建它的对象?
* 局部内部类无法在方法外部被访问,必须在方法里面创建它的对象,并且方法还要被执行,这样才会触发它的类加载局部内部类自身的特点
* > 1,访问权限修饰符
* 局部变量没有访问权限,局部内部类也是一样的
* 它的作用范围就在方法内部,要访问权限没有意义
* 同样的,它也不能用static修饰
*
* > 2,成员特点
* 局部内部类的成员特点和成员内部类比较相似,可以有普通成员,但是没有静态成员,可以有全局常量,但是必须是那些不触发类加载的
* 有构造器
* 有构造代码块
* 但是没有静态代码块
*
* > 3,定义位置
* 只要是成员位置就行了
* 一般来说更长见的还是方法中
*
* >
* > 4,继承和实现
* 用局部内部类来继承和实现一个外部类是非常常见的操作访问特点
局部内部类的访问特点:
* 1,内部类去访问外围类
* a,在外围类的成员方法中写一个局部内部类
* 可以直接访问,因为成员方法中有this指向当前对象(外围类对象)
* 如果出现同名的成员,用外围类类名.this区分同名
*
* b,在外围类的静态方法中写一个局部内部类
* 需要创建外围类对象才能够访问成员,如果同名就用相应的对象名区分
*
* 以上访问都不受访问权限限制
*
* 2,外围类访问内部类
* 访问不到
* 3,外部类访问内部类
* 访问不到
* 4,内部类访问其他类
* 可以访问,创建对象就行
* 都受访问权限限制
局部内部类使用注意事项:
在局部内部类的成员方法中使用方法的局部变量
只要局部内部类成员方法访问方法的局部变量那么它就变成常量
原因:从生命周期方面去想,方法局部变量生命周期和对象声明周期的冲突,如JVM图所示:
JVM内存图:
小练习:
内部类优缺点;
匿名内部类:
待补充!!!
Lambda表达式_在集合部分会广泛应用 好像是高级菜鸟装逼用的
待补充!!!
lambda表达式简化
Object类
getClass方法
这里是对Class类创建对象的阐述
/* Class对象是在类加载时,jvm帮助在堆上生成的,既然是类加载时期生成的,因为类加载只有一次,所以Class对象也只有一份 * 对于同一个类来说,它的Class对象是唯一的,独一份的 * 如果不是同一个类,那么它们的运行时Class对象必然不同 * 根据这一特点我们可以用来判断两个对象是否是同一个类生成的 * 类的对象和类对象的区别: * 类对象指的是Class对象,一个类独一份 * 类的对象是指new出来的对象,可以有很多个 */ public class Demo2 { public static void main(String[] args) { Student s = new Student(); Class stuClazz = s.getClass(); Student s2 = new Student(); Class stuClazz2 = s2.getClass(); Teacher t = new Teacher(); Class teacherClazz = t.getClass(); System.out.println(stuClazz == stuClazz2); System.out.println(teacherClazz == stuClazz); /*System.out.println(stuClazz.getName()); System.out.println(stuClazz.getSimpleName());*/ } } class Student{ } class Teacher{ }
toSring()方法
* toString()方法声明:
* public String toString()
* 这个声明平平无奇,只需要注意该方法有返回值,并且返回值是String字符串
* 作用:
toString方法注意事项
注意事项:
* 1,只要是用对象参与字符串的拼接或者直接输出一个对象,默认就是调用该类的toString方法
* 如果自身没有重写该方法,就去调用Object类的toString方法
*
* 2,idea的Debug模式,在打印对象的属性时,会自动调用toString方法
* toString方法就是为了打印对象的属性取值用的,不要给它乱加东西,尤其不要在里面做赋值操作
*
* 3,如果类中有别的引用类型,可以在返回语句中调用该引用类型的toString()方法
如下代码所示:
public class Demo {
public static void main(String[] args) {
// Student s = new Student(16,45);
/*Student s1 = new Student(19,45);
System.out.println(s1.age);*/
Student s = new Student(19, 54, new Teacher(28));
System.out.println(s);
}
}
class Student{
int age;
double score;
Teacher t;
public Student() {
}
public Student(int age, double score) {
this.age = age;
this.score = score;
}
public Student(int age, double score, Teacher t) {
this.age = age;
this.score = score;
this.t = t;
}
@Override
public String toString() {
age = 999;
System.out.println("hello");
return "年龄是:"+age+" 成绩是:"+score +"老师年龄是:"+t;
}
}
class Teacher{
int age;
public Teacher(int age) {
this.age = age;
}
@Override
public String toString() {
return "老师年龄是" + age;
}
}
equals方法
* 方法的声明: public boolean equals(Object obj)
* 只需要注意该方法返回值是布尔类型,方法的形参是一个Object类对象,意外着它可以传入所有的对象
* 作用:
* 指示方法的调用者对象和传入的对象是否相等,相等就返回true,不相等就返回false
*
* 怎么判断对象相等?
* 1,Object类当中equals方法是怎么判断对象相等的?
* public boolean equals(Object obj) {
* return (this == obj);
* }
* 比较的是地址,所以Object类当中equals方法认为完全是一个对象的所有引用对象才相等,这个条件很苛刻
*
* 2,我们理解的对象相等:
* a,如果两个对象不是一个类生成的,这两个对象没有可比性,肯定不相等
* b,如果两个对象是同一个类生成的,那么它们的行为是一致,只有成员变量取值是不一样的
* 所以认为只要是成员变量的取值相等,就是对象相等
* 如果想要根据我们的理解去比较两个对象,需要自己重写equals方法
重写equals方法的常规协定
接下来描述五个特性,附带代码,仅供参考
自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true
* 自己和自己比,应该返回true
*
* - 排他性:当比对的不是同种类型的对象或者是一个null时,默认返回false
*
* - 对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true
* 如果x=y,那么y=x
* 交换律
*
* - 传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true
* 那么x.equals(z) 应返回 true
* 如果x=y,y=z
* 那么x=z
* 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false
* 前提是对象上equals 比较中所用的信息没有被修改
* 多次调用该方法,只要比较的信息不变,那么结果就不能改变
*
* 思考: 如果用成员变量的取值去比较对象是否相等,能否同时满足对称性,传递性,一致性?
* 显然是可以的
* 所以只要通过成员变量的取值来去判断对象是否相等
* 就能够满足常规协定的后面三点要求public class Demo { public static void main(String[] args) { Cat c1 = new Cat(1,100); Cat c3 = c1; Cat c2 = new Cat(1,100); System.out.println(c1==c2); System.out.println(c1.equals(c2)); } } class Cat{ int age; double price; public Cat() { } public Cat(int age, double price) { this.age = age; this.price = price; } @Override public boolean equals(Object obj) { //满足自反性,判断:地址值相同才是自己 if (obj == this){ //自己和自己比返回的应该是true return true; } //满足排他性,判断不是自身类型生成,使用getClass()方法判断 //在前面要首先判断obj不是null if (obj == null || obj.getClass() != this.getClass()){ //如果obj是null用的是短路或,就无需进行后面的判断避免了空指针异常 //如果不是同种类型对象,没有可比性,应该返回false return false; } //通过成员变量取值来判断对象相等 //首先要做强转,代码走到这里,obj传入的对象一定和方法的调用者是同种类型对象,所以无需判断,直接强转 Cat target = (Cat) obj; if (target.age != this.age){ //如果age不同,对象肯定不相等直接返回false return false; } return this.price == target.price; } }
补充:
* 1,比较两个浮点类型的数据,最好不要用"=="号
* 推荐使用
* Double.compare(double d1,double d2) Float.compare(float f1,float f2)
* 该方法的返回值是一个int数值
* 如果返回值是0表示两个浮点数相等
* 如果返回值小于0,表示后面的大
* 如果返回值大于0,表示前面的大
*
* 2,如果想要计算两个浮点数的精确计算,需要使用BigDecimal这个数据类型* BigDecimal用来精确的表示一个浮点数,并且进行精确的计算
* BigDecimal是一个类,是一个引用数据类型
* 所以首先要学会创建一个它的对象* 构造方法最常用的:
* BigDecimal(String val) 将 BigDecimal 的字符串表示形式转换为 BigDecimal对象。
*
*
* BigDecimal的使用是有固定用途的,现在大家不必要学习,等到有需求了再用* > equals方法使用注意事项:
* - 对于任何非空引用值 x,x.equals(null) 都应返回 false
* - 不要使用一个null常量去调用方法,会引发程序错误,报空指针异常
*
* - 在方法中,我们只能对方法的参数进行校验,没办法校验调用者,代码如下所示:public class Demo { public static void main(String[] args) { /*Cat c1 = new Cat(1,100); Cat c3 = c1; Cat c2 = new Cat(1,100); System.out.println(c1==c2); System.out.println(c1.equals(c2));*/ Cat c1 = new Cat(1, 1000, new Person(18)); Cat c2 = new Cat(1, 1000, new Person(18)); System.out.println(c1 == c2); System.out.println(c1.equals(c2)); } } class Cat{ int age; double price; Person p; public Cat(int age, double price, Person p) { this.age = age; this.price = price; this.p = p; } public Cat() { } public Cat(int age, double price) { this.age = age; this.price = price; } /*@Override public boolean equals(Object obj) { //满足自反性,判断:地址值相同才是自己 if (obj == this){ //自己和自己比返回的应该是true return true; } //满足排他性,判断不是自身类型生成,使用getClass()方法判断 //在前面要首先判断obj不是null if (obj == null || obj.getClass() != this.getClass()){ //如果obj是null用的是短路或,就无需进行后面的判断避免了空指针异常 //如果不是同种类型对象,没有可比性,应该返回false return false; } //通过成员变量取值来判断对象相等 //首先要做强转,代码走到这里,obj传入的对象一定和方法的调用者是同种类型对象,所以无需判断,直接强转 Cat target = (Cat) obj; if (target.age != this.age){ //如果age不同,对象肯定不相等直接返回false return false; } //return this.price == target.price; return Double.compare(this.price, target.price)==0; }*/ //使用idea快捷键生成 @Override public boolean equals(Object o) { if (this == o) return true;//自反性 if (o == null || getClass() != o.getClass()) return false;// Cat cat = (Cat) o; if (age != cat.age) return false; if (Double.compare(cat.price, price) != 0) return false; return p.equals(cat.p); } } class Person{ int money; public Person() { } public Person(int money) { this.money = money; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return money == person.money; } }
* - 应该在外部写代码,防止使用一个null去调用方法
* - 如果类中有引用类型的成员变量,继续调用该引用类型的equal()方法判断