疑问
先来一段代码:
public class GenericFruit {
static class Fruit{
@Override
public String toString() {
return "fruit";
}
}
static class Apple extends Fruit{
@Override
public String toString() {
return "apple";
}
}
static class Person{
@Override
public String toString() {
return "Person";
}
}
static class GenerateTest<T>{
public void show_1(T t){
System.out.println(t.toString());
}
//在泛型类中声明了一个泛型方法,使用泛型E,这种泛型E可以为任意类型。可以类型与T相同,也可以不同。
//由于泛型方法在声明的时候会声明泛型<E>,因此即使在泛型类中并未声明泛型,编译器也能够正确识别泛型方法中识别的泛型。
public <E> void show_3(E t){
System.out.println(t.toString());
}
//在泛型类中声明了一个泛型方法,使用泛型T,注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一种类型。
public <T> void show_2(T t){
System.out.println(t.toString());
}
}
public static void main(String[] args) {
Person person = new Person(); //如果Person不声明为静态类时,会报错
Apple apple = new Apple();
GenerateTest<Fruit> generateTest = new GenerateTest<Fruit>();
//apple是Fruit的子类,所以这里可以
generateTest.show_1(apple);
//编译器会报错,因为泛型类型实参指定的是Fruit,而传入的实参类是Person
//generateTest.show_1(person);
//使用这两个方法都可以成功
generateTest.show_2(apple);
generateTest.show_2(person);
//使用这两个方法也都可以成功
generateTest.show_3(apple);
generateTest.show_3(person);
}
}
疑问:GenerateTest的main方法,在new一个Person对象和new一个Apple对象时,如果其不声明为static会报错,所以
1、这是 静态方法main的原因 吗?
写一个Demo来看一下:
那么问题更具体一些了:
为什么静态方法可以实例化其它非静态非内部类,但是却不可以实例化非静态内部类?
报错:
No enclosing instance of type Father is accessible. Must qualify the allocation with an enclosing instance of type Father (e.g. x.new A() where
x is an instance of Father).
答:可以参考:嵌套类
我理解为非静态内部类相当于是外部类Father的一个“成员变量”,实例化的话,需要通过使用 fa.new Father(); 的方式。
2、静态类中可以有非静态方法吗?
答:可以,但是一个在外部定义的类不能声明为static,声明为static的只能是静态内部类。
理论
一、静态类:
如果一个类要被声明为static,只有一种情况,就是静态内部类,如果在外部定义的类被声明为static,程序会编译不通过。
static关键字使得成员的存储位置为静态区;static是修饰类的成员的,而给类定义,即使是内部类,实例化后也是外部类的一个成员。
静态类中可以有 非静态 变量和方法。
静态类中的 非静态变量和方法 在 实例化的 静态类对象 中可以调用,不能直接使用静态类来调用。
二、静态变量
教室是同一个,可以是多个对象共享同一份数据,每个对象没有必要针对教室有一份自己独立的数据, 所以为了节约内存可以把所在教室声明为static对象:
一旦使用了static关键字,那么这样的内容不再属于对象自己,而是属于类,所以凡是本类的对象,都共享同一份。
static关键字可以用来修饰成员变量、成员方法。对应的变量、方法不属于对象而是属于类。
对于静态方法来说,可以通过对象名进行调用(正确,不推荐,因为容易误以为是一个普通的成员方法;在编译之后也会被javac翻译为“类名称.成员方法名”),也可以直接通过类名称来调用(强烈推荐)。
注意:
- 静态不能直接访问非静态
因为在内存中先有的静态内容,后有的非静态方法。“ 先人不知道后人,但是后人知道先人” - 静态方法当中不能使用this关键字
因为this代表当前对象,通过谁调用的方法,谁就是当前对象。
三、静态变量的内存图:
四、静态方法
在类中使用static修饰的静态方法会随着类的定义而被分配和装载入内存中;而非静态方法属于对象的具体实例,只有在类的对象创建时在对象的内存中才有这个方法的代码段。
静态方法只能访问 静态数据成员 和 静态数据方法。
静态方法中可以声明非静态变量。
public static void put(String set){
return new Abc().set(key);
}
静态方法内每次调用都会使用new产生一个新的Abc对象,原来的对象会一直存在,直到被垃圾回收机制收掉。
静态代码块:
典型用途: 用来一次性地对静态成员变量进行赋值
特点: 当第一次用到本类时,静态代码块执行唯一的一次,静态内容总是优先于非静态,所以静态代码块比构造方法先执行。
代码:
/*
* public class 类名称{
* static{
* //静态代码块的内容
* }
* }
*/
public class Father {
public Father() {
System.out.println("构造方法执行");
}
static{
System.out.println("静态代码块执行"); //静态代码块的内容
}
public static void main(String args[]) {
Father fa = new Father();
Father th = new Father();
}
}
执行结果:
静态代码块执行
构造方法执行
构造方法执行
参考视频:
https://www.bilibili.com/video/BV1ob411j7uh?p=5&t=279