《JavaSE-第八章》-代码块与内部类_java静态声明非法怎么改

}


public PeachBlossomIslandStudent(String name, String sex, double height) {
    this.name = name;
    this.sex = sex;
    this.height = height;

}



@Override
public String toString() {
    return "Student{" +
            "name='" + name + '\'' +
            ", sex='" + sex + '\'' +
            ", height=" + height +
            ",teacher="+ PeachBlossomIslandStudent.teacher+
            '}';
}
//静态方法
public static void flute(){
    System.out.println("碧海潮生曲");
}

public static void sword(){
    System.out.println("落英神剑掌");
}
//成员方法
public void study(){
    System.out.println("好好学习");

}

}


现在知道了如何使用static,那么如何访问被static修饰的成员呢?在java中被static修饰的成员是属于类的,而不是属于对象独有,所以我们一般是用类名.属性或者类型.方法名,来使用被static修饰的成员


使用static修饰的成员


代码示例



package Demo;

/**
* truth:talk is cheap, show me the code
*
* @author KC萧寒
* @description
* @createDate: 2022-05-14 09:34
*/

public class PeachBlossomIslandStudentText {
public static void main(String[] args) {
PeachBlossomIslandStudent s=new PeachBlossomIslandStudent(“陈玄风”,“男”,1.7);
PeachBlossomIslandStudent s2=new PeachBlossomIslandStudent(“梅超风”,“女”,1.70);
PeachBlossomIslandStudent s3=new PeachBlossomIslandStudent(“陆乘风”,“男”,1.70);
System.out.println(s);
System.out.println(s2);
System.out.println(s3);
PeachBlossomIslandStudent.sword();
PeachBlossomIslandStudent.flute();
s.sword();//错误使用
s.flute();//错误使用
}
}


切记被static修饰的成员本质上属于类,但是它又是被所有对象所共享,所以可以通过对象的引用去访问。这种方式的访问是不建议使用,我们通常访问静态成员使用类名去访问。


静态方法中无法使用实例成员变量


静态方法


![在这里插入图片描述](https://img-blog.csdnimg.cn/a81a02a522514434a785a476106df1ad.png#pic_center)


成员方法  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/748c20bfcc3048a9b0e836ae9dbb924d.png#pic_center)


对于静态的方法它属于类,不属于特定对象,所以它的形参列表中默认是没有this,没有this自然就不能使用成员变,而成员方法中的形参列表默认有this,这样我们才能调用当前类的成员。


#### ✈1.3static成员内存解析图


解析此代码



package Demo;

public class PeachBlossomIslandStudent {
private String name;
private String sex;
private double height;
public static final String teacher=“黄药师”;

//静态方法
public static void flute(){
    System.out.println("碧海潮生曲");
}

public static void sword(){
    System.out.println("落英神剑掌");
}
//成员方法
public void study(){
    System.out.println("好好学习");

}

public static void main(String[] args) {
    PeachBlossomIslandStudent s=new PeachBlossomIslandStudent();
    s.name="陈玄风";
    s.sex="男";
    s.height=1.90;
    PeachBlossomIslandStudent s2=new PeachBlossomIslandStudent();
    s2.name="梅超风";
    s2.sex="女";
    s2.height=1.70;
}

}


内存图


![在这里插入图片描述](https://img-blog.csdnimg.cn/cc1c1afb26974933b5548b25707089ad.png#pic_center)


#### ✈1.4static成员总结


成员变量特性


1. 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
2. 类变量存储在方法区当中
3. 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)
4. 可以通过对象的引用访问,也可以通过类名访问,建议使用类名访问


成员方法特性


1. 是类的方法,不属于对象。
2. 不能在静态方法中访问任何非静态成员变量
3. 可以通过对象调用,也可以通过类名.


static成员变量初始化


注意:静态成员变量一般不会放在构造方法中来初始化,构造方法中初始化的是与对象相关的实例属性


静态成员变量的初始化分为两种:就地初始化 和 静态代码块初始化。


1. 就地初始化 就地初始化指的是:在定义时直接给出初始值



public static final String teacher=“黄药师”;//就地初始化


接下来就来介绍代码块


### ✈2.代码块


代码块概念以及分类


使用 {} 定义的一段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:


1. 普通代码块
2. 构造块
3. 静态块
4. 同步代码块(暂时不介绍)


#### ✈2.1普通代码块


普通代码块:定义在方法中的代码块.


代码示例



public class Demo {
public static void main(String[] args) {
{
int age=99;
System.out.println(age);
}
age=9;
}
}


代码块中的age是局部变量,大括号是它的作用域即使用范围,所以代码外的age是无法使用的。这个普通代码块基本不用。


#### ✈2.2构造代码块


构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。


代码示例



public class Demo {
private int age;
private String name;
private String school;

public Demo() {
    System.out.println("无参构造器初始化");
}

{
    System.out.println("构造块初始化");
    age = 12;
    name = "小白";
    school = "家里蹲";
}

public void show() {
    System.out.println("name: " + name + " age: " + age + " schoo: " + school);
}

public static void main(String[] args) {
    Demo d = new Demo();
    d.show();
}

}


运行结果



构造块初始化
无参初始化
name: 小白 age: 12 schoo: 家里蹲


结论:构造块的初始化早于构造器的。


#### ✈2.3静态代码块


使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。


代码示例



public class Demo {
private int age;
private String name;
private static String school;

public Demo() {
    System.out.println("无参构造器初始化");
}

static {
System.out.println(“静态代码块初始化”);
school = “家里蹲”;
}

{
    System.out.println("实例代码块初始化");
    age = 12;
    name = "小白";
}

public void show() {
    System.out.println("name: " + name + " age: " + age + " schoo: " + school);
}

public static void main(String[] args) {
    Demo d = new Demo();
    d.show();
}

}


运行结果



静态代码块初始化
实例代码块初始化
无参构造器初始化
name: 小白 age: 12 schoo: 家里蹲


#### ✈2.4初始化顺序总结



package task;

public class LifeCycle {
//静态属性
private static String staticField = getStaticField();

//静态代码块
static {
    System.out.println(staticField);
    System.out.println("静态代码初始化");
}

//普通属性/成员属性
private String field = getField();

//普通方法块/实例代码块
{
    System.out.println(field);
    System.out.println("实例代码块初始化");
}

//构造函数初始化
public LifeCycle() {
    System.out.println("构造函数初始化");
}

public static String getStaticField() {
    String statiFiled = "静态属性初始化";
    return statiFiled;
}

public static String getField() {
    String filed = "普通属性初始化";
    return filed;
}

public static void main(String[] argc) {
    new LifeCycle();
}

}


运行结果



静态属性初始化
静态代码初始化
普通属性初始化
实例代码块初始化
构造函数初始化


初始化顺序优先级:静态属性>经静态代码块>实例属性>实例代码块>构造器


注意事项


1. 静态代码块不管生成多少个对象,其只会执行一次
2. 静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
3. 如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次合并
4. 实例代码块只有在创建对象时才会执行


### ✈3.内部类



> 
> 当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服 务,那么整个内部的完整结构最好使用内部类。在 Java 中,可以将一个类定义在另一个类或者一个方法的内部, 前者称为内部类,后者称为外部类。内部类也是封装的一种体现。
> 
> 
> 


内部类好比是连接佛珠的线将一颗一颗珠子连接在一起


![在这里插入图片描述](https://img-blog.csdnimg.cn/e709563284dd4947bebb0705dc4c827c.jpeg#pic_center)


代码示例



public class Outer {

public class Inner{

}

public static void main(String[] args) {
    new Outer();
}

}

//错误认知
public class A{

}

class B{
}
//A B是两个独立的类


注意事项


1. 定义在class 类名{}花括号外部的,即使是在一个文件里,都不能称为内部类
2. 内部类和外部类共用同一个java源文件,但是经过编译之后,内部类会形成单独的字节码文件


内部类的分类根据内部类定义的位置不同,一般可以分为以下几种形式:


1. 成员内部类(普通内部类:未static修饰的成员内部类 和 静态内部类:被static修饰的成员内部类)(在外部类中,内部类定义位置与外部类成员所处的位置相同,因此称为成员内部类。)
2. 局部内部类(不谈修饰符)、匿名内部类


#### ✈3.1实例内部类


即未被static修饰的成员内部类。


内部类中能不能定义静态成员?


通过代码来验证



public class Outer {

public class Inner{
static int age=90;
}

public static void main(String[] args) {
    new Outer();
}

}


运行结果



java: 内部类Demo.Outer.Inner中的静态声明非法
修饰符 ‘static’ 仅允许在常量变量声明中使用


此时看来是不能的,当给statc修饰的成员变量加上final就可以使用了



public class Outer {

public class Inner{
static final  int age=90;
}

public static void main(String[] args) {
    new Outer();
}

}


结论:内部类中要定义静态成员必须使用static final修饰


实例内部类中能不能定义静态成员方法?


代码示例



public class Outer {

public static void study(){
    System.out.println("好好学习");
}

public class Inner{
static final  int age=90;
}

public static void main(String[] args) {
    new Outer();
}

}


答案是可以


**成员内部类创建对象的格式**



格式:外部类名.内部类名 对象名 = new 外部类构造器.new 内部类构造器();
范例:Outer.Inner in = new Outer().new Inner();


实例内部类代码大全示例



package task;

public class Outer {
private static int a;
static int b;
int c;

public void methodA() {
    Outer.Inner in=new Outer().new Inner();
    in.name="hmr";
    System.out.println(in.name);
    a = 99;
    System.out.println(a);
}

public static void methoB() {
    Outer.Inner in=new Outer().new Inner();
    in.name="叶子秋";
    System.out.println(in.name);
    b = 100;
    System.out.println(b);
}
// 实例内部类:未被static修饰
public class Inner {
    int c;
    static final int age=19;
    String name;
    public void mathodC() {
        // 在实例内部类中可以直接访问外部类中:任意访问限定符修饰的成员
        a = 90;
        b = 100;
        methodA();
        methoB();
        // 如果外部类和实例内部类中具有相同名称成员时,优先访问的是内部类自己的
        c = 900;
        System.out.println(c);
        // 如果要访问外部类同名成员时候,必须:外部类名称.this.同名成员名字
        System.out.println(Outer.this.c);
    }
}

}


测试类



package task;

public class OuterText {

public static void main(String[] args) {
    // 要访问实例内部类中成员,必须要创建实例内部类的对象
	// 而普通内部类定义与外部类成员定义位置相同,因此创建实例内部类对象时必须借助外部类
	// 外部类:对象创建 以及 成员访问
    Outer o=new Outer();
    // 创建实例内部类对象,要得到内部类先要创建外部类
    //Outer.Innner in=new Outer.new Inner(); 方式一
    
    Outer.Inner in=o.new Inner();//方式二
    
    in.mathodC();
}

}


注意事项


1. 外部类中的任何成员都可以被在**实例内部类方法**中直接访问
2. 实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束
3. 在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外部类名 称.this.同名成员 来访问
4. 实例内部类对象必须在先有外部类对象前提下才能创建
5. 实例内部类的非静态方法中包含了一个指向外部类对象的引用
6. 外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。


成员内部类的访问


1、成员内部类中是否可以直接访问外部类的静态成员?


**可以,外部类的静态成员只有一份可以被共享访问。**


2、成员内部类的实例方法中是否可以直接访问外部类的实例成员?


**可以的,因为必须先有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员。**


#### ✈3.2静态内部类


**什么是静态内部类?**


* 有static修饰,属于外部类本身。
* 它的特点和使用与普通类是完全一样的,类有的成分它都有,只是位置在别人里面而已。


**静态内部类创建对象的格式:**



格式:外部类名.内部类名 对象名 = new 外部类名.内部类构造器;


代码示例



package task;

public class OuterStatic {
private int a;
static int b;

public void methodA(){
    a=90;
    System.out.println(a);
}
public static void methodB(){
    b=100;
    System.out.println(b);
}

public static class InnerStatic{

    public void method(){
       // a=90;
        b=78;
        methodB();
       // methodA();
    }

}

}


静态内部类注意事项


1. 在静态内部类中只能访问外部类中的静态成员
2. 创建静态内部类对象时,不需要先创建外部类对象


#### ✈3.3局部内部类


局部内部类放在方法、代码块、构造器等执行体中


代码示例



package Demo;

public class Outer {
int a = 90;
public void study() {
int b = 99;
// 局部内部类:定义在方法体内部
// 不能被public、static等访问限定符修饰
class Inner {
public void print() {
System.out.println(a);
System.out.println(b);
}
}
// 只能在该方法体内部使用,其他位置都不能用
Inner in = new Inner();
in.print();
}

}


局部内部类的类文件名为: 外部类$N内部类.class


局部内部类了解即可


#### ✈3.4匿名内部类


本质上是一个没有名字的局部内部类,定义在方法中、代码块中、等


作用:简化代码


**特点总结:**


* 匿名内部类是一个没有名字的内部类。
* 匿名内部类写出来就会产生一个匿名内部类的对象。
* 匿名内部类的对象类型相当于是当前new的那个的类型的子类类型。


代码一



public class Text {
public static void main(String[] args) {
Animal a=new Tiger();
a.run();
}
}

class Tiger extends Animal {
@Override
public void run() {
System.out.println(“老虎跑的快!”);
}
}

abstract class Animal {
public abstract void run();
}


通过匿名内部类简化代码



public class Text {
public static void main(String[] args) {
Animal a = new Animal() {
@Override
public void run() {
System.out.println(“老虎跑的快!”);
}
};
a.run();
}
}

abstract class Animal {
public abstract void run();
}


使用匿名内部类实现老师,学生同时打游戏



package inner;
//简化版一
public class Text2 {
public static void main(String[] args) {
IPlayGame ip = new IPlayGame() {
@Override
public void PlayGame() {
System.out.println(“学生打游戏!”);
}
};
playGame(ip);
System.out.println(“---------------”);
IPlayGame ip2 = new IPlayGame() {
@Override
public void PlayGame() {
System.out.println(“老师打游戏!”);
}
};
playGame(ip);
}

public static void  playGame(IPlayGame i){
    System.out.println("开始游戏");
    i.PlayGame();
    System.out.println("结束游戏");
}

}

interface IPlayGame {
void PlayGame();
}
//简化版二
//Lambda只能简化接口中只有一个抽象方法的匿名内部类形式(函数式接口)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值