🔥博客主页: 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;
}
@Override
public 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..10000
public 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..10000
public 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的,在接口中都是默认的,所以不用加abstract
public void start();
public void stop();
}
//phone
package com.hspedu.interface_;
//Phone类实现Usb接口,也就是Phone类需要实现usbInterface接口声明的方法
public class phone implements Usb{
@Override
public void start() {
System.out.println("手机开始工作");
}
@Override
public void stop() {
System.out.println("手机停止了工作");
}
}
//camera
package com.hspedu.interface_;
public class camera implements Usb{
//实现接口,本质上就是把接口的方法完成
@Override
public void start() {
System.out.println("相机开始工作了");
}
@Override
public 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{
@Override
public 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{
@Override
public void show() {
}
@Override
public 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{
@Override
public void work() {
System.out.println("手机工作中");
}
public void call(){
System.out.println("手机可以打电话");
}
}
class Camera implements Usb1{
@Override
public 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和m2
m2();
System.out.println("n1=" + n1);//2.可以直接访问外部类的所有成员,包括私有的,输出800
System.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{
@override
public void cry(){
System.out.println("老虎在叫");
}
* */
//7.jdk在底层创建匿名内部类Outer04$1,立即马上创建了一个实例,并把地址返回给tiger
//8.匿名内部类使用一次就不能再使用了
A tiger = new A(){//相当于是new了是实现A接口类的对象
@Override
public 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"){
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
};
father.test();//检查一下
//基于抽象类的匿名内部类,抽象类的方法就必要要实现了
Animal animal = new Animal(){
@Override
void 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() {
@Override
public void show() {
System.out.println("调用了匿名内部类");
}
});
//这是我自己写的
IL demo8 = new IL(){
@Override
public 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() {
@Override
public void ring() {
System.out.println("懒猪起床了");
}
});
cell.alarmclock(new Bell() {
@Override
public 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
判断输出结果