【java】类和对象2

7.static成员

7.1static修饰成员变量

static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,

是所有对象所共享的。

【静态成员变量特性】

1. 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中

2. 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问

3. JDK7及以前,HotSpot(Java虚拟机)中存储在方法区,JDK8及之后,类变量存储在Java堆中

4. 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)

class Student {
    public String name;
    public int age;
    public int id;
    public static String school = "西安";//学校  不属于对象 属于类(公用的静态的成员变量[方法区]
                                        //生命周期伴随一生
    public static void main(String[] args) {
      // 静态成员变量可以直接通过类名访问
      System.out.println(Student.classRoom);
      Student s1 = new Student("Li leilei", "男", 18, 01);
      Student s2 = new Student("Han MeiMei", "女", 19, 02);
     // 也可以通过对象访问:但是classRoom是三个对象共享的
      System.out.println(s1.classRoom);
      System.out.println(s2.classRoom);
      //System.out.println(student1.school);//不合理  不合法  不建议这样写
      System.out.println(Student.school);//合理的  建议这样(用类名)访问静态成员
     }
}

7.2 static修饰成员方法

一般类中的数据成员都设置为private,而成员方法设置为public,那设置之后,Student类中

classRoom属性如何在类外访问呢?

class Student {
    private String name;//封装:对外隐藏了类内部实现的细节
    private int age;    //需要set和get
    private int id;
    public static String school = "西安";

    public Student() {
        System.out.println("不带参数的构造方法!");
    }

    public class TestStudent {
        public static void main(String[] args) {
           System.out.println(Student.classRoom);
        }
    }
}

编译失败:Error:(10, 35) java: classRoom 在 extend01.Student 中是 private 访问控制

 那static属性应该如何访问呢?

Java中,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。静态

成员一般是通过静态方法来访问的.

public static String getClassRoom(){
    return classRoom;
 }

我们就需要借助get和set来访问了。 

【静态方法特性】
1. 不属于某个具体的对象,是类方法
2. 可以通过对象调用,也可以通过类名.静态方法名(...)方式调用,更推荐使用后者
3. 静态方法没有隐藏的this引用参数,因此不能在静态方法中访问任何非静态成员变量

public static String getClassRoom(){
  System.out.println(this);
  return classRoom;
}

编译失败:Error:(35, 28) java: 无法从静态上下文中引用非静态 变量 this

public static String getClassRoom(){
  age += 1;
  return classRoom;
}

编译失败:Error:(35, 9) java: 无法从静态上下文中引用非静态 变量 age

 4. 静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法

传递this引用

public static String getClassRoom(){
  doClass();
  return classRoom;
}

 编译报错:Error:(35, 9) java: 无法从静态上下文中引用非静态 方法 doClass()

 5. 静态方法无法重写,不能用来实现多态.

7.3 static成员变量初始化

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

例属性。

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

 1. 就地初始化

    就是在在定义时直接给出初始值。

private static String classRoom = "Bit306"; 

 2. 静态代码块初始化

在类中直接已用static直接定义:

static  {
        school = "hafuo";
        System.out.println("静态代码块 -》定义在类内部,和构造方法同级,主要初始化静态成员");
    }

7.4static修饰的变量计算问题

class Test {
    public int a1;
    public static int a2;
}
public class TextDemo2 {
    public static void main(String[] args) {
        Test test1 = new Test();
        test1.a1++;
        test1.a2++;
        Test test2 = new Test();
        test2.a1++;
        test2.a2++;
        System.out.println("a1="+test1.a1);
        System.out.println("a2="+Test.a2);
    }
}

a1=1
a2=2

static是在方法区存储的。

8. 代码块

8.1 代码块概念以及分类

分类:普通代码块
           构造块
           静态块
           同步代码块

class Student {
    private String name;
    private int age;
    private int id;
    public static String school = "西安";


    public Student() {
        System.out.println("不带参数的构造方法!");
    }

    public Student(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.id = id;
        System.out.println("带有三个参数的构造方法!");
    }

    {
        this.name = "实例(构造)代码块";

        System.out.println("实例代码块 -》定义在类内部,和构造方法同级");
    }

    static  {
        //school = "hafuo";
        System.out.println("静态代码块 -》定义在类内部,和构造方法同级,主要初始化静态成员");
    }
    public void sleep() {
        {
            int x = 10;//作用域
            System.out.println("普通代码块");
        }
        //System.out.println(x);
    }
    public static void main4(String[] args) {
        Student student1 = new Student();
        System.out.println("===========");
        Student student2 = new Student();
        //先静态在实例,静态只执行一次,在类加载的时候就被执行了。
    }
}

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAVGhlRGV2aWNl,size_20,color_FFFFFF,t_70,g_se,x_16

 

8.2 普通代码块

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

成员变量

【注意事项 】
实例代码块优先于构造方法执行,因为编译完成后,编译器会将实例代码块中的代码拷贝到每个构造方法第一条语句前.

8.4 静态代码块

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

注意事项
静态代码块不管生成多少个对象,其只会执行一次

1.静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的

2.Java代码在经过编译器编译之后,如果要运行必须先要经过类加载子系统加载到JVM中才能运

行。在加载阶段:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAVGhlRGV2aWNl,size_20,color_FFFFFF,t_70,g_se,x_16

3.在链接阶段第二步准备中会给静态成员变量开辟空间,并设置为默认值,在初始化阶段,会执行

静态代码块中的代码。(了解:关于类加载过程后序JVM中会详细讲解)

4.如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次合并,最

终放在生成的<>方法中,该方法在类加载时调用,并且只调用一次。

5.实例代码块只有在创建对象时才会执行.


综合这些概念和代码的使用,我们更加清晰的了解了代码块这一知识点。 

9. 内部类

当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为

外部事物提供服务,那么整个内部的完整结构最好使用内部类。在 Java 中,可以将一个类定义在

另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。

但是有些定义在class 类名{}花括号外部的,即使是在一个文件里,都不能称为内部类

public class A{
 
}
class B{
 
}

A 和 B是两个独立的类,彼此之前没有关系

内部类和外部类共用同一个java源文件,但是经过编译之后,内部类会形成单独的字节码文件 。

9.1 内部类的分类

public class OutClass {
  // 成员位置定义:未被static修饰 ---> 普通内部类
  public class InnerClass1{
 }
  // 成员位置定义:被static修饰 ---> 静态内部类
  static class InnerClass2{
 }
  public void method(){
    // 方法中也可以定义内部类 ---> 局部内部类:几乎不用
    class InnerClass5{
   }
 }
}

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

1. 成员内部类(普通内部类:未static修饰的成员内部类 和 静态内部类:被static修饰的成员内部类)

2. 局部内部类(不谈修饰符)、匿名内部类

注意:内部类其实日常开发中使用并不是非常多,大家在看一些库中的代码时候可能会遇到的比较

多,日常开始中使用最多的是匿名内部类

9.2 成员内部类

在外部类中,内部类定义位置与外部类成员所处的位置相同,因此称为成员内部类。

9.1.1 普通内部类

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

class OuterClass {
    public int date1 = 1;
    private int date2 = 2;
    public static int date3 = 3;

    //实例内部类
    class InnerClass {
        public  int date1 = 1000;
        public  int date4 = 4;
        private int date5 = 5;
        //public static int date6 = 6; //实例内部类需要对象引用,与static冲突  但是可以用 
                                       //static final 修饰。
        public static final int date6 = 6;

        public void test() {
            System.out.println(OuterClass.this.date1);
            System.out.println(date2);
            System.out.println(date3);
            System.out.println(this.date4);
            System.out.println(this.date5);
            System.out.println(date6);

            System.out.println("InnerClass的test()方法");
        }
    }

    public void test2() {
        OuterClass.InnerClass innerClass2 = new OuterClass().new InnerClass();
        System.out.println(innerClass2.date1);
        System.out.println("OutClass的test()方法");
    }

    public static void main(String[] args) {
        //InnerClass innerClass = new OutClass.InnerClass();
        OuterClass outerClass = new OuterClass();
        System.out.println(outerClass.date1);
        //System.out.println(outerClass.date1);
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        innerClass.test();
        System.out.println(innerClass.date4);
        OuterClass.InnerClass innerClass2 = new OuterClass().new InnerClass();
        innerClass2.test();
        }
}
实例内部类的引用格式:
OuterClass.InnerClass innerClass2 = new OuterClass().new InnerClass();

   外部类的引用与普通类相同。

【注意事项】
1. 外部类中的任何成员都可以被在普通内部类方法中直接访问

2. 普通内部类所处的成员与外部类成员位置相同,因此也受public、private等访问限定符的约束

3. 在内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外

部类名称.this.同名成员 来访问

4. 普通内部类对象必须在先有外部类对象前提下才能创建

5. 普通内部类的非静态方法中包含了一个指向外部类对象的引用

6. 外部类中,不能直接访问内部类中的成员,如果要访问必须先要创建外部类的对象。

9.1.2 静态内部类

被static修饰的内部成员类称为静态内部类。

class OuterClass2 {
    public int date1 = 1;
    private int date2 = 2;
    public static int date3 = 3;

    //静态内部类
    static class InnerClass2 {
        public int date1 = 1000;
        public int date4 = 4;
        private int date5 = 5;
        public static final int date6 = 6;
        //public OuterClass2 out = new OuterClass2();//(2)
        public OuterClass2 out;//(3)
        public InnerClass2() {
        }
        public InnerClass2(OuterClass2 out) {
           this.out = out;
        }
        public void text() {
           //OuterClass2 outerClass2 = new OuterClass2();//(1)
            System.out.println(date1);
            System.out.println(out.date2);
            System.out.println(date3);//可以
            System.out.println(this.date4);
            System.out.println(this.date5);
            System.out.println(date6);
            System.out.println("InnerClass的test()方法");
        }
    }
    public static void main1(String[] args) {
        OuterClass2.InnerClass2 innerClass2 = new OuterClass2.InnerClass2();
        //此时不需要拿到外部类对象,更加有效
    }
}

我们在内部要访问外部的成员的方法:

1,

class OuterClass2 {
    public int date1 = 1;
    private int date2 = 2;
    public static int date3 = 3;

    //静态内部类
    static class InnerClass2 {
        //public int date1 = 1000;
        //public int date4 = 4;
        //private int date5 = 5;
        //public static final int date6 = 6;
        public OuterClass2 out = new OuterClass2();
        public void text() {
            System.out.println(date3);//可以
        }
}

2,

class OuterClass2 {
    public int date1 = 1;
    private int date2 = 2;
    public static int date3 = 3;        

    public InnerClass2() {

    }
       
    public InnerClass2(OuterClass2 out) {
       this.out = out;
    }
    public void text() {
       System.out.println(date3);//可以
    }
}

【注意事项】
1. 在内部类中只能访问外部类中的静态成员
2. 创建内部类对象时,不需要先创建外部类对象
3. 成员内部类,经过编译之后会生成独立的字节码文件,命名格式为:外部类名称$内部类名称

9.3 局部内部类

定义在外部类的方法体或者{}中,该种内部类只能在其定义的位置使用,一般使用的非常少,此处简单了解下语法格式:

public class OutClass {
  int a = 10;
  public void method(){
    int b = 10;
    // 局部内部类:定义在方法体内部
    // 不能被public、static等访问限定符修饰
    class InnerClass{
      public void methodInnerClass(){
        System.out.println(a);
        System.out.println(b);
     }
   }
    // 只能在该方法体内部使用,其他位置都不能用
    InnerClass innerClass = new InnerClass();
    innerClass.methodInnerClass();
 }
  public static void main(String[] args) {
    // OutClass.InnerClass innerClass = null; 编译失败
 }
}

【注意事项】
1. 局部内部类只能在所定义的方法体内部使用
2. 不能被public、static等修饰符修饰
3. 编译器也有自己独立的字节码文件,命名格式:外部类名字$x内部类名字.class,x是一个整数。
4. 几乎不会使用

9.4 匿名内部类

===========================   接口  =========================

10. 对象的打印

public class Person {
  String name;
  String gender;
  int age;
  public Person(String name, String gender, int age) {
    this.name = name;
    this.gender = gender;
    this.age = age;
  }
  public static void main(String[] args) {
    Person person = new Person("77","男", 18);
    System.out.println(person);
  }
}

打印结果:day20210829.Person@1b6d3586

但是我们想要打印 “"77","男", 18”,我们只能自己写一个print方法。

    public void print() {
        System.out.println(" 姓名:"+name+" 年龄:"+age+" ID:"+id);
    }

但是我们发现这样的话,如果数据量一大,会发现写起来十分困难。那么我们就又有一种简便的方

法来供我们使用。


单击鼠标右键,选择Generate---->继续选择toString();即可。


    @Override  //----》用来检验重写。
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }
   

                                                                  END 

 

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值