学习大数据的第14天——Java面向对象(内部类、常用类(Object类))
注意匿名内部类(重点)后期编写Flink的时候需要!!!!
内部类
内部类:
把类定义在其他类的内部,我们称之为内部类
内部类有哪些特点:
1、内部类可以访问外部类的成员,包括私有
2、外部类要想访问内部类的成员,必须要创建内部类的对象
按照内部类在类中定义的位置不同,可以分为如下两种格式:
成员位置(成员内部类)
局部位置(局部内部类)
class Outer{
//定义在成员的位置上(成员内部类)
class Inner{
}
public void fun(){
//定义在局部范围内(局部内部类)
class Inner{
}
}
}
成员内部类:
1、定义在类的成员位置上
2、内部类可以访问外部类的成员,包括私有的
正确创建成员内部类对象的格式
外部类名.成员内部类名 对象名 = new 外部类名().new 成员内部类名();
Outer.Inner oi = new Outer().new Inner();
成员内部类常见的修饰符:
private: 其他类不能直接创建内部类的对象,要想使用被private修饰内部类成员,必须在本类中间接的创建对象调用
static: 内部类如果是被satic修饰的时候,只能访问外部类中静态成员
当内部类是被静态所修饰的时候,出现了另外一种创建内部类的方式
格式如下:
外部类名.内部类名 对象名 = new 外部类名.内部类名();
Outer.Inner oi = new Outer.Inner();
直接通过类名直接调用
Outer.Inner.fun();
面试题:
/*
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public void show() {
int num = 30;
System.out.println(?);
System.out.println(??);
System.out.println(???);
}
}
}
在控制分别输出:30,20,10
*/
如何在System.out.println()中填写语句,控制分别输出:30,20,10
class Outer5{
public int num = 10;
class Inner5 {
public int num = 20;
public void show() {
int num = 30;
System.out.println(num); //30
System.out.println(this.num); //20
//Outer5和Inner5不是继承关系,没有super关键字
// System.out.println(super.num); //10
// System.out.println(new Outer5().num);
System.out.println(Outer5.this.num);
}
}
}
public class InnerClassDemo5 {
public static void main(String[] args) {
Outer5.Inner5 oi5 = new Outer5().new Inner5();
oi5.show();
}
}
局部内部类:
1、定义在方法中的类
2、局部内部类可以直接访问外部类中所有成员
3、要想使用局部内部类中的方法,在定义局部内部类的成员方法中,创建局部内部类对象调用方法。
class Outer6{
private int num = 10;
public void fun(){
int num2 = 20;
class Inner6{
int num3 = 300;
public void show(){
num3 = 30;
//在局部内部类中引用的本地的变量必须是最终变量或者实际上的最终变量
//通过反编译工具观察发现,存在局部内部类的方法中定义的局部变量自动加上了final关键字
//在JDK1.8之后会自动加上final关键字
// num2 = 22;
num = 44;
System.out.println(num);
System.out.println(num2);
System.out.println(num3);
}
}
Inner6 inner6 = new Inner6();
inner6.show();
}
}
匿名内部类:
/*
interface A{
b();
c();
}
class B implements A{
b(){...};
c(){...};
}
A a = new B();
a.b();
a.c();
匿名内部类
语句定义格式:
new 类名(可以是抽象类也可以具体的类)/接口(){
要重写的方法;
};
上面的案例通过匿名内部类改进:
A a = new A(){
b(){...}
c(){...}
};
匿名内部类存在的前提:
要存在一个类或者是一个接口,这个类可以是具体的类也可以是抽象的类
*/
interface Inter{
public abstract void show();
public abstract void show2();
}
//class B implements Inter{
//
// @Override
// public void show() {
//
// }
//
// @Override
// public void show2() {
//
// }
//}
//Inter i = new B()
class Outer7{
public void fun(){
//使用匿名内部类的形式创建对象调用show方法
new Inter(){
@Override
public void show() {
System.out.println("这是show方法");
}
@Override
public void show2() {
System.out.println("这是show2方法");
}
}.show();
//使用匿名内部类的形式创建对象调用show2方法
new Inter(){
@Override
public void show() {
System.out.println("这是show方法");
}
@Override
public void show2() {
System.out.println("这是show2方法");
}
}.show2();
System.out.println("======================================");
//想一想,我现在的接口中,只有两个方法,方法的个数比较少,没调用一个方法,都要new一下,并且new之后的内容都是一样的
//如果以后接口中的方法很多的时候,你再用这样的方法,就会很麻烦
//怎么改进呢?
//利用接口多态的形式给匿名内部类起名字
Inter inter = new Inter(){
@Override
public void show() {
System.out.println("这是show方法");
}
@Override
public void show2() {
System.out.println("这是show2方法");
}
};
inter.show();
inter.show2();
}
}
public class InnerClassDemo7 {
public static void main(String[] args) {
Outer7 outer7 = new Outer7();
outer7.fun();
}
}
面试题:
/*
interface Inter { void show(); }
class Outer { //补齐代码 }
class OuterDemo {
public static void main(String[] args) {
Outer.method().show();
}
}
要求在控制台输出”HelloWorld”
*/
interface Inter2{
void show();
}
class Outer8{
//1、根据main方法调用的代码推出第一个结论:method()是静态的,可以直接通过类名访问/调用
//2、根据main方法中调用完method()方法之后,还能继续调用方法,我们判定method()是有返回值的
//而再观察后发现,show()方法恰好是Inter2接口中的方法,所以返回值类型是接口Inter2类型
//根据调用method()方法的参数是空,所以判定method()方法没有参数
public static Inter2 method(){
// return new Inter();
// Student student = new Student();
// return student;
return new Inter2() {
@Override
public void show() {
System.out.println("HelloWorld");
}
};
}
}
//class Student implements Inter2{
// @Override
// public void show() {
// System.out.println("HelloWorld");
// }
//}
public class InnerClassDemo9 {
public static void main(String[] args) {
Outer8.method().show();
}
}
常用类(Object类):
相对路径:将该项目作为根目录(com.shujia.wyh.day13.changyonglei.Student)
绝对路径/完整路径:带上盘符(D:\IdeaProjects\bigdata15\src\com\shujia\wyh\day13\changyonglei\Student.java)
Object:Class Object是类Object结构的根。 每个班都有Object作为超类。
所有对象(包括数组)都实现了这个类的方法。 java中每个类都直接或者间接的继承了Object类
Object类中的方法:
public int hashCode()返回对象的哈希码值。
支持这种方法是为了散列表,如HashMap提供的那样。
注意:这里的哈希码值是根据哈希算法计算出来的一个值。这个值和地址有关系,但是这里返回的地址值并不是实际的地址值
你们现在就简单理解为地址值的另外一种表现形式。
public final Class getClass() //返回的是该对象的类对象
返回此Object的运行时类。 返回的类对象是被表示类的static synchronized方法锁定的对象。
public String toString()返回对象的字符串表示形式。
一般来说, toString方法返回一个“textually代表”这个对象的字符串。
结果应该是一个简明扼要的表达,容易让人阅读。 建议所有子类覆盖此方法。
该toString类方法Object返回一个由其中的对象是一个实例,该符号字符`的类的名称的字符串@ ”和对象的哈希码的无符号的十六进制表示。 换句话说,这个方法返回一个等于下列值的字符串:
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
Integer:
public static String toHexString(int i)
返回整数参数的字符串表示形式,作为16位中的无符号整数。 将哈希值转化一个地址值。
我们虽然掌握了toString()的方法使用,但是呢打印的一个结果是一个我们看不懂的地址值,换句话我们拿到这个结果没有意义
返回对象的字符串表示形式,实际上我们更想去看的是该对象中各个成员变量的值。
恰好toString()方法是被public修饰的,也恰好它的返回值是String类型的,所以我们可以在其他类中对它做重写
今后无特殊情况不需要自己手写,自动生成即可。
一个标准类的4.0版本:
成员变量:使用private关键字修饰
构造方法:一个无参。一个带所有参数的方法。
成员方法:setXxx(…)/getXxx()
toString():自动生成即可,替代掉我们之前show方法。
protected void finalize():
当垃圾收集确定不再有对该对象的引用时,垃圾收集器在对象上调用该对象。
一个子类覆盖了处理系统资源或执行其他清理的finalize方法。
你们就简单理解这个方法为用于垃圾回收的,什么时候回收,不确定
GC机制,标记法。
protected Object clone() 创建并返回此对象的副本。
执行特定的克隆工作。
其他包中的子类要想使用被protected修饰的方法,使用super关键字调用。
clone的方法Object执行特定的克隆操作。
首先,如果此对象的类不实现接口Cloneable ,则抛出CloneNotSupportedException 。
一个类要想使用clone(),就必须实现Cloneable接口
通过观察API发现,Cloneable接口中没有常量,也没有抽象方法
今后看到类似于Cloneable一样,里面什么都没有的接口,我们称之为标记接口。
拷贝在IT行业中常见两种:
浅拷贝:
浅拷贝是指我们拷贝出来的对象的内部引用类型变量和原来的对象内部引用类型变量的地址值是一样的(指向的是同一个对象)
但是整个拷贝出来的对象和新对象不是同一个地址值。
深拷贝:
全部拷贝对象的内容,包括内存的引用类型也进行拷贝,拷贝的时候,重新创建一个对象,成员变量值和原来被拷贝的一样。
但是后续再对拷贝后的引用数据类型变量做修改,不会影响到原来被拷贝的。