JAVA 学习 面试(七)类

JAVA 学习 面试(七)类_第1张图片

作用:

  • 提供搜索和定位类、接口、枚举和注释等
  • 防止命名冲突(包采用树形目录的存储方式,同包中类的名字不同,不同包中类的名字可以相同。)
  • 访问控制(拥有包访问权限的类才能访问某个包中的类)

java.lang:包含语言支持类(例如分类,用于定义基本数据类型,数学运算)。该软件包会自动导入。
java.io:包含分类以支持输入/输出操作。
java.util:包含实现像链接列表,字典和支持等数据结构的实用类; 用于日期/时间操作。
java.applet:包含用于创建Applets的类。
java.awt:包含用于实现图形用户界面组件的类(如按钮,菜单等)。
java.net:包含支持网络操作的类。

Object类

.java源文件中只能有一个public类,包中public的类的类名必须和文件名相同

main方法一个特殊的函数,作为程序的入口,可被JVM调用,(String[] args):main函数的参数,类型是一个数组,该数组中的元素为字符串数组,每个类中有且仅有一个主函数

Java类都有一个共同的祖先类:Object类(实体类),Object类拥有的方法:hashcode()、equals()、toString()、getClass()、wait、notify()、notifyAll()、finalize()、clone()

## Class类和Object类的关系 
Object类和Class类没有直接的关系
Object类是一切java类的父类,对于普通的java类,即便不声明,也是默认继承了Object类
Class类是用于java反射机制的,一切java类,都有一个对应的Class对象,他是一个final类
Class 类的实例表示正在运行的 Java 应用程序中的类和接口

clone方法
    保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常
hashCode方法

    该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价
内部类
  1. 成员内部类

    • 成员内部类作为外部类的成员,可以访问外部类的私有成员或属性
    • 当外部类变量与方法和内部类同名,内部类默认访问自己的成员变量或方法,引用外部变量使用时加类名.this:类名.this.变量名、类名.this.方法名()
    • 外部类不能直接使用内部类的成员和方法,可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法。
  2. 静态内部类

    • 静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问
    • 外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员
    • 创建静态内部类的对象时,不需要通过外部类的对象,可以直接创建 内部类 对象名= new 内部类();
  3. 局部内部类(方法内、代码块内、构造器内)

    • 局部内部类中不可定义静态变量,可以访问外部类的局部变量(即方法内的变量),但是变量必须是final的。
    • 不能在方法内部类中创建可变的局部变量。
    • 可以访问外围类的成员变量。如果是static方法,则只能访问static修饰的成员变量。
  4. 匿名内部类

    public class TestDemo {
       public static void main(String[] args) {
           Person per = new Person() {
               public void work() {// 匿名内部类自定义的方法work
                   System.out.println("work方法调用");
               }
               @Override
               public void eat() {// 实现接口的的方法eat
                   System.out.println("eat方法调用");
               }
           };
           per.eat();// 可调用
           per.work();// 出错,不能调用,因为 Person per = new Person()创建的是Person的对象,而非匿名内部类的对象。匿名内部类连名字都没有,无法实例化调用对象,但继承父类的方法和实现的方法是可以正常调用的
       }
    }
    interface Person {
       public void eat();
    }
    

注意:

  • 要创建 Inner class 的实例,必须先创建一个包裹类的实例(创建静态内部类的对象时,不需要通过外部类),也正因如此,内部类不能定义静态成员(不然怎么访问呢?)
  • 内部类的声明会覆盖掉包裹类的声明,解决办法:OuterClass.this
  • 局部类只能访问 final or effectively final 的外部变量,当局部类只使用一次时,可以考虑使用匿名类。
抽象类
  • 使用abstract关键字修饰的类
  • 有构造器,但不能实例化
  • 若子类没有实现/覆盖父类所有的抽象方法,那么子类也得作为抽象类(抽象派生类),需要使用abstract修饰
  • abstract不能用来修饰private、static、final、属性、构造器
  • 抽象类中可以没有抽象方法(一般最好有)
Static
  1. 修饰属性

    将类中的属性划分为 静态属性(静态变量) 和非静态属性(实例变量)
    静态变量随着类的加载而加载。可以通过  类.静态变量  的方式进行调用,早于对象的创建
    由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中
    静态属性举例:System.out; Math.PI;
    
  2. 修饰方法

    ①随着类的加载而加载,可以通过 类.静态方法 的方式进行调用  
    ②静态方法中,只能调用静态的方法或属性
    ③静态方法中,不能使用this关键字、super关键字,因为没有对象
    
  3. 修饰代码块

    代码块的作用是:限制局部变量的作用范围,提前释放内存,一般结合if,while ,for等关键字使用
        3.每创建一个对象,就执行一次非静态代码块
        4.作用:创建对象时对对象的属性进行初始化
        5.非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
    static代码块的作用:用于给类进行初始化,在加载的时候就执行,并且只执行一次。一般用于加载驱动
    
构造方法
  • 所有的class都必须有一个构造方法,如果没有在代码里声明,系统会自动生成一个公有无参的构造方法,没有返回类型,其默认的返回类型为对象类型本身
  • 所有的子类构造器都要求在第一行代码中调用父类构造器,如果不写,系统默认去调用父类的无参构造器。
  • 不能被 static、final、synchronized、abstract 和 native 修饰(原因:构造方法用于初始化一个新对象,所以用 static 修饰没有意义;构造方法不能被子类继承,所以用 final 和 abstract 修饰没有意义;多个线程不会同时创建内存地址相同的同一个对象,所以用 synchronized 修饰没有必要
## 子类调用父类构造方法:
当子类构造方法调用父类无参构造方法,一般都是默认不写的,要写的话就是super(),且要放在构造方法的第一句
当子类构造方法要调用父类有参数的构造方法,必须要用super(参数)来调用父类构造方法,且要放在构造方法的第一句
当子类的构造方法是无参构造方法时,必须调用父类无参构造方法。
代码块

局部代码块

  • 位置:局部位置(方法内部)
  • 作用:限定变量的生命周期,尽早释放,节约内存
  • 调用:调用其所在的方法时执行

构造代码块

  • 位置:类成员的位置,就是类中方法之外的位置
  • 作用:把多个构造方法共同的部分提取出来,共用构造代码块
  • 调用:每次调用构造方法时,都会优先于构造方法执行,也就是每次new一个对象时自动调用,对对象的初始化

静态代码块

  • 位置:类成员的位置,用static修饰的代码块
  • 作用:对类进行初始化,当new多个对象时,只能加载第一个new对象,执行一次
  • 调用:new对象时自动调用,并只能调用一次
//A类
public class A {
static {
    Log.i("HIDETAG", "A静态代码块");
}
private static C c = new C("A静态成员");
private  C c1 = new C("A成员");
{
    Log.i("HIDETAG", "A代码块");
}
static {
    Log.i("HIDETAG", "A静态代码块2");
}
public A() {
    Log.i("HIDETAG", "A构造方法");
}
}
//B类
public class B extends A {
private static C c1 = new C("B静态成员");
{
    Log.i("HIDETAG", "B代码块");
}
private C c = new C("B成员");
static {
    Log.i("HIDETAG", "B静态代码块2");
}
static {
    Log.i("HIDETAG", "B静态代码块");
}
public B() {
    Log.i("HIDETAG", "B构造方法");
} 
}
//C类
public class C {
public C(String str) {
    Log.i("HIDETAG", str + "构造方法");
}
}
// 主函数
public static void main(String[] args) {
		B a = new B();
}
//输出:
I/HIDETAG: A静态代码块
I/HIDETAG:A静态成员构造方法
I/HIDETAG:A静态代码块2
I/HIDETAG:B静态成员构造方法
I/HIDETAG:B静态代码块2
I/HIDETAG:B静态代码块
I/HIDETAG:A成员构造方法
I/HIDETAG:A代码块
I/HIDETAG:A构造方法
I/HIDETAG:B代码块
I/HIDETAG:B成员构造方法
I/HIDETAG:B构造方法

执行顺序:

父类的静态成员和代码块——>子类的静态成员和代码块——>父类成员初始化和代码块——>父类构造方法——>子类成员初始化和代码块——>子类构造方法

继承
  • Java抽象类可以继承抽象类
  • 抽象类也可以继承具体类。但是,这有一个前提条件,即具体类必须具有明确的构造函数。如果具体类没有写构造函数,系统会自动生成默认的无参构造器,这意味着没有写构造函数的具体类也可以被抽象类继承。然而,一旦将具体类的无参构造器设置访问修饰符为 private,那么抽象类就不能再继承这个具体类了
  • Java不支持多重继承呢,因为会导致菱形继承问题:一个类同时继承了两个具有共同父类的类时,如果这两个父类有相同的方法,子类将无法确定使用哪个父类的方法。这样就导致了二义性的产生
上下转型
  1. 向上转型

    向上转型就是子类的对象赋给父类的引用或(父类的引用指向子类的对象)

    Person p1=new Man();
    Person p1=new Woman();
    
  2. 向下转型

    向上转型无法调用子类特有的属性和方法,为了能够调用子类特有的属性和方法,就有了向下转型。向下转型是子类对象被父类引用之后,再把父类引用强转成子类,强转时叫做向下转型。

    使用强转时,可能出现ClassCastException的异常。会用到instanceof关键字

    Person p1=new Man();//向上转型
    if(p1 instanceof Man){
        Man m2 = (Man)p1;
        m2.work();
        System.out.println("******Man******");
    }
    
this关键字

它在方法内部使用,即这个方法所属对象的引用;它在构造器内部使用,表示该构造器正在初始化的对象。

// 调用方法
public void getInfo(){
		System.out.println("姓名:" + name) ;
		this.speak();
	}
// 调用属性
public boolean compare(Person p){
		return this.name==p.name;
	}
// 调用本类的构造器
public Person(String name){
		this(); // 调用本类中的无参构造器
    this(name) ; // 调用有一个参数的构造器
		this.name = name ;
	}

父类方法中的this也可能代表的是调用该父类方法的子类的实例对象,abstract类中的非抽象方法中的this对象只能是代表子类自己的实例对象指针

父类的final修饰方法,意味着子类无法去重写该方法,但不影响子类对象直接去调用父类的final方法,所以final方法中的this对象既可以代表子类自己的实例对象指针,又可以代表父类本身的实例对象指针

你可能感兴趣的:(java,学习,面试)