🔥博客主页: A_SHOWY
🎥系列专栏:力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_
一、类变量和类方法
1.1 引出类变量
类变量的快速入门:类变量被所有对象实例共享
package com.hspedu.static_;public class ChildGame {public static void main(String[] args) {Child child1 = new Child("白骨精");child1.join();child1.count++;Child child2 = new Child("白骨精");child2.join();child2.count++;Child child3 = new Child("白骨精");child3.join();child3.count++;//类变量可以通过类名来访问System.out.println("共有" + Child.count +"小孩加入了游戏");}
}class Child{private String name;//定义一个变量child,是一个类变量(静态变量)//该变量最大的特点是会被Child类的所有对象实例共享public static int count = 0;public Child(String name) {this.name = name;}public void join(){System.out.println(name + "加入了游戏..");}
}
1.2 类变量内存布局
两种说法,有一点是肯定的,静态变量是被对象共享的,一种说法是在堆里,另一种说法是在静态域(jdk8以前)里面。
两点共识:
- static变量被同一个类的所有对象共享
- static类变量,在类加载的时候就生成
1.3 类变量定义
类变量也叫静态变量/静态属性,是该类所有对象共享的变量
1.4 如何定义类变量
访问修饰符 static 数据类型 变量名;//常用
static 访问修饰符 数据类型 变量名;
1.5 如何访问类变量
1. 类名.类变量名 // 推荐
2. 对象名.类变量名 //静态变量的访问修饰符的访问权限和范围和普通的属性是一样的
package com.hspedu.static_;public class VisitStatic {public static void main(String[] args) {//类变量随着类的加载创建的,即使没有创建对象实例也可以访问,当然通过对象实例也能访问System.out.println(A.name);A a = new A();System.out.println(a.name);}
}
class A{//类变量public static String name = "cpy";}
如果static前面变成private,那么另一个就不能访问他了,遵循基础规则
*1.6 类变量使用细节
1.7 类方法基本介绍
形式:只需要普通方法前面加一个static
调用:类名.类方法名或者对象名.类方法名 (满足访问修饰符的权限)
小例子:总学费
package com.hspedu.static_;public class StaticMethod {public static void main(String[] args) {Stu tom = new Stu("tom");tom.payFee(100);Stu mary = new Stu("mary");mary.payFee(200);Stu.showFee();}
}class Stu{private String name;//定义一个类变量累计学生的学费static private double fee = 0;public Stu(String name) {this.name = name;}//static:静态方法,静态方法只能访问静态属性static public void payFee(double fee){Stu.fee += fee;//累计}static public void showFee(){System.out.println("总学费有" + Stu.fee);}}
1.8 类方法经典使用场景
如果我们不创建实例,也可以掉某个方法,及当作工具来使用! ,这时把方法做成静态方法合适
*1.9 类方法使用细节
4)注释:不能用是因为类变量和类方法随着类的加载而加载,类的加载比对象的创建要早,如果使用this或者super的话,会找不到这个对象5)静态方法只能访问静态成员
1.10 课堂练习
(1)答案:9,10,11
(2)答案:
1.id++那里错的,类方法中只能访问静态变量和静态方法
2.输出是0和1,注意构造器这里不能是static所以这里没错
(3)答案:
1.在静态方法中不能使用this
2.total的值最后等于4
总结:
- 静态方法只能访问静态成员
- 非静态方法可以访问所有成员
- 编写代码时候仍要遵守访问权限规则
1.11 main方法
注释:
1.一定记住:main方法由虚拟机调用
2.把public去了就直接不能执行了
5.问:你这个字符串数组【String【】 args】形参从哪里传进去的:是在执行这个程序的时候,在后边传进去的参数形成的数组
这就是为什么我们每次访问非静态成员,都要创建个对象 !
package com.hspedu.static_;public class Main01 {private static String name;private int age;private static void sayhi(){System.out.println("hi");}public static void main(String[] args) {//可以直接使用name//1.静态方法main可以访问本类的静态成员System.out.println(name);sayhi();//2.静态方法main不可以访问本来的非静态成员//age;//包括方法//3.静态方法main要访问本类的静态成员要创建对象先Main01 main01 = new Main01();System.out.println(main01.age);}
}
1.12 补充:在idea中传递参数给java程序
package com.hspedu.static_;public class Main02 {public static void main(String[] args) {for (int i = 0; i < args.length; i++) {System.out.println(args[i]);}}
}
二、代码块
2.1 基本介绍
2.2 基本语法
2.3 快速入门
代码块的调用要优先于构造器,就比如构造器重载的时候,三个构造器,第一个构造器是一个参数,第二个是两个参数,第三个是三个参数,但是他们的内容都是一样的,这样就不如搞一个代码块放在最前面
2.4 代码块细节
- 代码块前面加一个staitc表示静态代码块,作用就是对类进行初始化,随着类的加载而执行,只会执行一次。如果是普通代码块,每次创建一个对象就执行,每创建一次就执行一次。
- (重要)类什么时候被加载:1)当创建对象实例的时候(new)2)创建子类对象实例的时候,父类也会被加载 (比如说父类中有一个代码块,子类中也有一个,然后创建一个子类对象,他就会先加载一个父类的代码块再加载一个子类代码块) 3)使用类的静态成员时(这个类中的代码块会被加载)
- 注意,如果只使用类的静态成员,普通代码块并不会执行!!!,因为类加载和这个普通代码块没有关系,普通代码块是构造器的补充,普通代码块调用了,他就被调用了
package com.hspedu.static_;public class CodeBlockDetail01 {public static void main(String[] args) {System.out.println(DD.n1);} } class DD{public static int n1 = 8888;//静态代码块static{System.out.println("DD的静态代码块被执行");}{System.out.println("DD的普通代码块被执行");} }
- (重点+难点) 创建对象的时候,在一个类中的调用顺序
//1.静态代码块和静态属性初始化,谁在前面谁先 package com.hspedu.static_;public class Stati从Method2 {public static void main(String[] args) {AA aa = new AA();} } class AA{static {System.out.println("静态代码块被调用");}//静态属性初始化private static int a = getN1();private static int getN1(){System.out.println("getN1被调用");return 100;} }
- 构造器的最前面其实隐藏了super和调用普通代码块
- (综合带继承)顺序总结:先把静态的走完,剩下的从父类开始各走各的
- 静态代码块只能调用静态成员,普通代码块能调用所有代码块
在new的时候首先要进行类的加载,再进行创建对象 所以类的加载和静态相关的部分全部执行。设计到创建对象的时候就从父类开始了,因为子类隐藏了super()和普通代码块和普通属性的初始化等。参考5,其实综合起来核心就是
2.5 代码块相关题目
题目一:答案:in static block ,total = 100,total = 100(因为类加载以后静态代码块就不再执行了)
题目二(重点题目):答案:
静态成员sam初始化,static块执行,|(该普通成员了),Sam1成员初始化 ,|(该构造器了)Test默认构造函数被调用
三、单例设计模式
3.1 什么是单例模式
单例:就是单个的实例,大概意思是指该类只能有一个对象实例
3.1.1 饿汉式
(因为是私有的,在类内创建,所以在还没有使用到的时候就已经创建好了, 饿汉式可能造成创建了对象没有使用就造成了浪费)
注:私有化的目的是防止直接new一个对象
这里有个很奇妙的点,就是为什么创建的对象和这个提供的公共方法都必须是static因为首先如果方法不是static那么需要先创建类才能调用,但是这个是个私有的,没法创建类,所以必须是static,而静态方法只能用静态成员,所以内部创建的对象也必须static ,形成了完美闭环,非常的神奇。
package com.hspedu.static_;public class SingleTon {public static void main(String[] args) {GirlFriend instance = GirlFriend.getInstance();System.out.println(instance);GirlFriend instance1 = GirlFriend.getInstance();System.out.println(instance1);System.out.println(instance1 == instance);}
}class GirlFriend{private String name;//1.将构造器私有化//2.在类的内部直接创建对象(该对象是static的)//3.提供一个公共的static方法,返回gf对象private static GirlFriend gf = new GirlFriend("小国子");//只要类加载就创建对象private GirlFriend(String name) {this.name = name;}public static GirlFriend getInstance() {return gf;}@Overridepublic String toString() {return super.toString();}
}
3.1.2 懒汉式
单例模式的对象通常是重量级的对象,如果你创建了没有用就浪费了。饿汉式可能造成创建了对象但是没有使用的弊端。
package com.hspedu.static_;public class SingleTon2 {public static void main(String[] args) {System.out.println(Cat.n1);//这样的话不会创建对象,只进行类加载Cat instance = Cat.getInstance();System.out.println(instance);Cat instance2 = Cat.getInstance();System.out.println(instance2);System.out.println(instance2 == instance);}
}
class Cat{public static int n1 = 100;private String name;private static Cat cat;//1.仍然私有化构造器//2.定义一个私有的静态属性的对象//3.提供一个公共的static方法,可以返回Cat对象private Cat(String name) {this.name = name;}public static Cat getInstance() {if(cat == null) {cat = new Cat("小cat");}return cat;}
}
代码中判断是否为空的目的,是假如说他再次创建对象肯定就不是空的了,这时候就不需要再重新创建一个对象,直接返回原有Cat对象即可,保存的单例模式的特征。
四、final关键字
4.1 基本介绍
4.2 细节
关于final修饰的静态属性初始化位置: 可以这样理解:因为是static和final,那么在类加载的时候就要创建好相应的属性,所以在构造器的时候修改,就违反了final不可修改的规定 。同时static在类加载的时候就要给值,它等不到你构造器创建对象!
注释5:它都不能被继承了,都没有重写的必要了,一般我们重写都是继承了以后,想要特殊功能
注释7:从下列代码和结果可以看到直接使用类的静态成员导致类加载,但是final能抑制这个类加载,所以不会输出静态代码块!
package com.hspedu.static_;public class SingleTon2 {public static void main(String[] args) {System.out.println(BBB.num);}
}
class BBB{public final static int num = 100000;static {System.out.println("BBB静态代码块被执行");}
}
4.3 练习
4.3.1 练习1
//1.在定义的时候赋值
class Circle{private double radius;private final double PI = 3.14;public Circle(double radius) {this.radius = radius;}
}
//2.在构造器的时候赋值
class Circle{private double radius;private final double PI;public Circle(double radius) {this.radius = radius;PI = 3.14;}
}
//3.在代码块中赋值
class Circle{private double radius;private final double PI;public Circle(double radius) {this.radius = radius;}{PI = 3.14;}public double calArea() {return PI * radius * radius;}
}
}
4.3.2 练习2
错误,++x修改了final修饰的值,但是形参加上final是对的
五、抽象类
5.1 抽象类的引出
父类方法的不确定性:当父类的某些方法需要声明,但是又不确定如何实现的时候,可以将其声明为抽象方法,那么这个类就是抽象类 ,一般来说抽象类会被继承,由其子类来实现
5.2 抽象类的细节
- 抽象类不能被实例化
- 抽象类可以没有抽象方法
- 一旦包含了抽象方法,那么这个类必须声明为抽象类
- abstract只能修饰类和方法,但是不能修饰属性和其他的
- 抽象类的本质还是类,所以类内部还是可以拥有任何可以拥有的方法
- 抽象类不能有主体,即不能实现
- 如果一个类继承了抽象类,它必须实现抽象类的所有方法,除非他自己也声明了抽象类//只要有方法体{}就称为实现了
- 抽象方法不能使用private ,final,static修饰,因为这些关键字和重写都是冲突的,private和final好理解,static的话:static修饰的方法是静态方法,其可以直接被类调用。而abstract是修饰的方法是抽象方法,即无代码体的方法,不能被直接调用,需要子类或者实现类去编写完整的方法处理逻辑了才能使用。
5.3 抽象类练习
1)错误,因为final不能被继承,所以你这里抽象了,后边没法实现
2)错误static关键字和方法重写无关,具体看上面的第八条。
3)不行,因为私有的别人不能重写
4)太简单了不写了
5.4 抽象类最佳实践——模板设计模式
思路1:最容易想到的
发现代码冗余,他们都有公共的代码部分,就是计算开始和结束时间,我们可以分别把这个抽出来,然后去改job但是还是很麻烦
package com.hspedu.static_;public class AABB {//计算任务//1..10000public void job(){//得到开始的时间long start = System.currentTimeMillis();int num = 0;for (int i = 1; i <= 100000000; i++) {num += i;}//得到结束的时间long end = System.currentTimeMillis();System.out.println("执行的时间是" + (end - start));}
}
package com.hspedu.static_;public class BB {public void job(){//得到开始的时间long start = System.currentTimeMillis();int num = 0;for (int i = 1; i <= 800000; i++) {num *= i;}//得到结束的时间long end = System.currentTimeMillis();System.out.println("执行的时间是" + (end - start));}
}
思路2:抽象模板类(抽象类+动态绑定机制)
其实核心思想就是普通方法嵌套抽象方法,这样子只需要改抽象方法就行了
package com.hspedu.static_;abstract public class Template {public abstract void job();//抽象方法public void calculateTime(){long startTime = System.currentTimeMillis();job();//动态绑定机制,子类没有起找父类,然后执行方法看编译类型long endTime = System.currentTimeMillis();System.out.println(endTime - startTime);}
}package com.hspedu.static_;public class AABB extends Template{//计算任务//1..10000public void job(){//得到开始的时间long start = System.currentTimeMillis();int num = 0;for (int i = 1; i <= 100000000; i++) {num += i;}}
}package com.hspedu.static_;public class BB extends Template {public void job(){int num = 0;for (int i = 1; i <= 800000; i++) {num *= i;}}
}package com.hspedu.static_;public class Test {public static void main(String[] args) {AABB aabb = new AABB();aabb.calculateTime();BB bb = new BB();bb.calculateTime();}
}
六、接口
6.1 快速入门
//USb接口
package com.hspedu.interface_;public interface Usb {//规定的接口的相关方法,接口中的方法都是public 和abstract的,在接口中都是默认的,所以不用加abstractpublic void start();public void stop();}//phone
package com.hspedu.interface_;
//Phone类实现Usb接口,也就是Phone类需要实现usbInterface接口声明的方法
public class phone implements Usb{@Overridepublic void start() {System.out.println("手机开始工作");}@Overridepublic void stop() {System.out.println("手机停止了工作");}
}//camera
package com.hspedu.interface_;public class camera implements Usb{//实现接口,本质上就是把接口的方法完成@Overridepublic void start() {System.out.println("相机开始工作了");}@Overridepublic void stop() {System.out.println("相机停止了工作");}
}//computer
package com.hspedu.interface_;
public class computer {//编写一个方法,计算机工作public void work(Usb usb){//通过接口使用方法usb.start();usb.stop();}
}//Interface类
package com.hspedu.interface_;public class Interface01 {public static void main(String[] args) {//创建手机,创建对象camera camera = new camera();phone phone = new phone();//创建计算机computer computer = new computer();computer.work(phone);//把手机接入到计算机System.out.println("===========");computer.work(camera);//把相机接入到计算机}
}
这里在computer类中其实在形参部分有一个向上转型的思想,父类的引用指向子类的对象
6.2 基本介绍
demo:
//Ainter接口
package com.hspedu.interface_;public interface AInter {//写属性public int n1 = 19;//写方法public void hi();//在接口中,抽象方法可以省略abstract关键字//在jdk8后可以有默认实现方法,需要加default!default public void ok(){System.out.println("ok");}//在jdk8后可以加静态方法public static void cry(){System.out.println("cry...");}
}//interface02类
package com.hspedu.interface_;public class Interface02 {public static void main(String[] args) {}
}//如果一个类 implements实现接口,需要将接口的所有抽象方法全部都实现
class A implements AInter{@Overridepublic void hi() {System.out.println("hi");}
}
如果一个类 implements实现接口,需要将接口的所有抽象方法全部都实现 !
6.3 应用场景
核心就是统一管理
这里其实又用到了向上转型,这里用个static就是为了不创建对象了简单测试一下
6.4 注意事项和使用细节
1.接口不能实例化,接口的作用是让别的类去实现它,再用实现它的类去实例化
2.接口中所有的方法是public方法,接口抽象方法中可以不用 abstract修饰
3.一个普通类实现接口就必须把该接口的所有接口都实现,可以使用alt+enter解决
4.抽象类实现接口,可以不用实现接口的方法
5.一个类可以同时实现多个接口
interface IB{void show();
}
interface IC{void hi();
}class pig implements IB,IC{@Overridepublic void show() {}@Overridepublic void hi() {}
}
6.接口中的属性,其实都是public static final 的,比如int a = 1;其实就是public static final int a = 1;(必须初始化)
7.接口中属性的访问形式:接口名.属性名
8.一个接口不能继承其他的类,但是能继承多个其他接口
9.接口的修饰符只能是public和默认
6.5 接口练习
这三个都完全正确,static属性可以被直接使用,在这里有点像继承,这里要注意当final修饰类的时候才说明不能被继承
6.6 接口和继承类的比较
简单理解:实现机制对我们单继承机制的补充 ,就比如小猴子继承了老猴子的东西,但是想学飞行或者游泳需要实现小鸟的飞行和小鱼的游泳
6.7 接口的多态特性
1.其实就是向上转型:父类的引用指向子类的对象
2. 多态数组
用到了判断运行类型instanceof + 向下转型去调用特有方法
package com.hspedu.interface_;public class interfacePoly {public static void main(String[] args) {Usb1[] usbs = new Usb1[2];usbs[0] = new Phone();usbs[1] = new Camera();for (int i = 0; i < usbs.length; i++) {usbs[i].work();//动态绑定,和运行类型绑定if(usbs[i] instanceof Phone){((Phone) usbs[i]).call();//向下转型}}}
}interface Usb1{void work();
}
class Phone implements Usb1{@Overridepublic void work() {System.out.println("手机工作中");}public void call(){System.out.println("手机可以打电话");}
}
class Camera implements Usb1{@Overridepublic void work() {System.out.println("相机工作中");}
}
3.接口存在多态传递的现象
6.8 接口课堂练习
第一句话接口里面的等价于 public static final int x = 0;
pX函数父类是B,接口是A,这个x不明确是谁,以下方式可以解决
总结:
七、内部类
7.1 基本介绍
补:类的五大成员
属性、方法、构造器、代码块、内部类
7.2 内部类的分类
7.3 局部内部类
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名
package com.hspedu;public class localinnner {public static void main(String[] args) {Outer outer = new Outer();outer.m1();}
}
class Outer{//外部类private int n1 = 100;private void m2(){System.out.println("m2执行");}//私有方法public void m1(){//1.局部内部类常常定义在外部类的局部位置,方法内//3.不能添加访问修饰符,但是可以用final修饰final class Inner{//局部内部类本质还是类private int n1 = 800;//和外部的n1重名了,遵守就近原则public void m1(){//5.局部内部类可以直接访问外部类的成员,比如下面,直接访问了外部类的n1和m2m2();System.out.println("n1=" + n1);//2.可以直接访问外部类的所有成员,包括私有的,输出800System.out.println("外部类的n1" + Outer.this.n1);//想访问外部类的n1的话用类名 + this.属性名//OUter.this的本质是外部类的对象,即谁调用了m1代码,这个Outer.this就指向哪个对象 }}
// class Inner2 extends Inner{
// }//6.外部类在方法中,可以创建Inner对象,然后调用方法,必须在作用域中Inner inner = new Inner();inner.m1();}//4.作用域:仅仅在定义它的方法或者代码块中// 代码块中写内部类{class Inner03{}}}
7.4 匿名内部类(最重要)
说明:匿名内部类是定义在外部类的局部位置,比如方法中并且没有类名
1) 本质是类 2)内部类 3)该类没有名字 4)同时还是一个对象
我的理解是就是这个匿名内部类起到一个简化作用,在做一个基于接口或者基于别的类的时候,只想用一次,每次调用接口都要创建一个新的类,那你创建一个匿名内部类省略了创建类的步骤 ,简化开发。这个匿名内部类用一次就没有了,你再new就不行了就是这个Outer04,但是返回的实例那个对象可以反复使用
demo1基于接口的匿名内部类
public class Anonymous {public static void main(String[] args) {Outer04 outer04 = new Outer04();outer04.method();}
}
class Outer04{private int n1 = 10;public void method(){
// A tiger = new Tiger();
// tiger.cry();//基于接口的匿名内部类//1.需求:想使用IA接口,并创建对象//2.传统方式,写一个类,实现该接口//3.这个Tiger这个类我可能只用一次就不用了,有点罗嗦,不同的动物叫都要写一个类//4.可以使用匿名内部类简化开发//5.tiger的编译类型?IA//6.tiger的运行类型?就是在这个匿名内部类 XXXX=>Outer04$1/** 我们看底层,底层会分配一个类名* class XXXXX implements A{@overridepublic void cry(){System.out.println("老虎在叫");}* *///7.jdk在底层创建匿名内部类Outer04$1,立即马上创建了一个实例,并把地址返回给tiger//8.匿名内部类使用一次就不能再使用了A tiger = new A(){//相当于是new了是实现A接口类的对象@Overridepublic void cry() {System.out.println("老虎叫唤");}};System.out.println("tiger的运行类型" + tiger.getClass());tiger.cry();}
}interface A{//接口public void cry();
}//class Tiger implements A{
// public void cry(){
// System.out.println("老虎在叫");
//
// }
//}class Father{public Father(String name) {}public void test(){}
}
demo2基于类的匿名内部类
public class Anonymous {public static void main(String[] args) {Outer04 outer04 = new Outer04();outer04.method();}
}
class Outer04{//分析//1.father的编译类型 Father//2.father的运行类型Outer04&2//3.底层创建匿名内部类,由于Father类里面什么都没有,所以这里可以什么也没有,如果是抽象类,那里面的方法必须要实现//个人理解:学到这里匿名内部类其实就是实例化对象,同时重写一些类的方法或者实现接口/*class Outer04&2 extends Father{}**///4.同时也直接返回了匿名内部类Outer04&2的对象//5.注意这个地方的参数列表会传递给构造器,这里的jack其实可以理解为super后边的那个参数Father father = new Father("jack"){@Overridepublic void test() {System.out.println("匿名内部类重写了test方法");}};father.test();//检查一下//基于抽象类的匿名内部类,抽象类的方法就必要要实现了Animal animal = new Animal(){@Overridevoid eat() {System.out.println("小狗吃骨头");}};animal.eat();System.out.println("father对象的运行类型" + father.getClass());//OUter04&2}
}
class Father{public Father(String name) {System.out.println("接收到了name");}public void test(){}
}abstract class Animal{void eat(){}
}
7.5 匿名内部类实践(使用场景)
demo1 用作实参直接传递
package com.hspedu.interface_;public class innerclassExercise
{public static void main(String[] args){//本质上是一个接口的匿名内部类f1(new IL() {@Overridepublic void show() {System.out.println("调用了匿名内部类");}});//这是我自己写的IL demo8 = new IL(){@Overridepublic void show() {System.out.println("调用了匿名内部类");}};demo8.show();}//静态方法,形参是接口类型public static void f1(IL il){il.show();}}//接口
interface IL{void show();
}
demo2 上一个demo的实例(自己能做出来牛逼)
package com.hspedu.interface_;public class innerclaseeexercise2 {public static void main(String[] args) {Cellphone cell = new Cellphone();cell.alarmclock(new Bell() {@Overridepublic void ring() {System.out.println("懒猪起床了");}});cell.alarmclock(new Bell() {@Overridepublic void ring() {System.out.println("小伙伴上课了");}});}
}
interface Bell{void ring();
}class Cellphone{public void alarmclock(Bell bell){bell.ring();}
}
7.6 成员内部类
说明:成员内部类是定义在外部类的成员位置,并且没有static修饰
1.需要成员内部类定义在外部内的成员的位置上
2.可以添加任意的访问修饰符,因为他本身就是一个成员(public,protected等)
第六点比较重要,外部其他类去使用成员内部类,主要有两种方法
//第一种方式
//如何理解:把Outer08去掉以后就是一个正常的实例化,加上Outer08就是内部的一个类的实例化,相当于把inner08()当作outer08的成员,就是一个语法问题
OUter08.Inner08 inner08 = outer08.new Inner08();//就像访问成员一样
//第二种方式,在外部类中写一个方法,可以返回一个Inner08的对象
//该方法直接返回Inner08的实例
public Inner08 getInner08Instance(){return new inner08();
}Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
7.如果外部类和内部类的成员重名了,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员可以使用外部类名.this.成员去访问,和前面那个局部内部类是一样的
7.7 静态内部类
说明:静态内部类是定义在外部类的成员位置,并且有static修饰
package com.hspedu.interface_;public class memberinnnerClass {public static void main(String[] args) {Outer10 outer10 = new Outer10();outer10.m1();//8.外部其他类去访问静态内部类//第一种方法,静态内部类可以通过类名直接访问的(满足访问权限)Outer10.Inner10.var()Outer10.Inner10 inner10 = new Outer10.Inner10();inner10.say();//第二钟方式,编写一个可以返回静态内部类的静态实例Outer10.Inner10 inner101 = outer10.getInner10();inner101.say();//第三种方式,这里直接不用创建对象了Outer10.getInner10_().say();}
}
class Outer10{//外部类private int n1 = 10;private static String name = "张三";private static void crt(){}//Inner10就是一个静态内部类//1.放在外部类的成员位置//2.使用了static修饰public static class Inner10{//9.名字重复就近原则private static String name = "py";public void say(){
// System.out.println(n1);这里是报错的,因为静态类只能访问静态成员//3.可以访问外部类的所有静态成员,但不能访问非静态成员//4.可以添加任意访问修饰符,因为他的地位就是一个成员System.out.println(name);//9.想访问外部类name,这里不需要加this,因为静态成员不需要类名.属性名调用,以前的this指的是类名System.out.println(Outer10.name);crt();//6.静态内部类访问外部类的成员可以直接访问所有的静态成员}}//5.作用域 :同其他成员为整个整体//7.外部类如果要访问内部类的静态成员,要先创建对象再访问,m1就是outer10的一个方法,去访问内部类的say方法public void m1(){Inner10 inner10 = new Inner10();inner10.say();}//把他想象成一个静态成员public Inner10 getInner10(){return new Inner10();}//可以加一个static,因为静态方法可以访问静态的,因为这个Inner10是静态的public static Inner10 getInner10_(){return new Inner10();}
}
补:小总结
7.8 习题1
判断输出结果