Java类和对象(2)

六、封装

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互

在Java中主要通过类和访问权限实现封装,可以将数据和方法结合在一起,而访问权限用来控制方法或者字段能否直接在类外使用;访问权限可以限定类中成员的可见性,也可以控制类的可见性。
Java中的四种访问限定符:public、protected、default、private
在这里插入图片描述

public:都可以看到
protected:主要在继承中使用
default(默认权限):同一个包中的都知道,对于外人就是隐私
private:只有自己知道,其他人都不知道

一般情况下,成员变量设置为 private,成员方法设置为 public
修饰类(外部类)只能使用public或默认

为了更好的管理类,把多个收集在一起成为一组,称为软件包
包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式;

在同一个工程中允许存在两个相同的类,只要处在不同的包中就可以

导入包中的类
方法一

public class TestDate {

    public static void main(String[] args) {
        java.util.Date date = new java.util.Date();
         //得到一个毫秒级别的时间戳;如果想看到正常的时间还需要格式化
        System.out.println(date.getTime());
    }
}

优点:不会发生冲突
缺点:麻烦

运行结果

1649238358096

方法二

//使用import语句导入包
import java.util.Date;
public class TestDate {

    public static void main(String[] args) {
        Date date = new Date();
        System.out.println(date.getTime());
    }
}

如果还需要使用 java.util 中其他的类,可以使用

import java.util.*

优点:使用较为简单
缺点:可能会发生冲突
比如:在 import java.util.* 和 import java.sql.*这两个包中都有Date类,对Date的引用不明确,此时会出现歧义,导致编译出错;这种情况下需要使用完整的类名,即方法一。

方法三

例:

//100平方根
public class Date {
    public static void main(String[] args) {
        System.out.println(Math.sqrt(100));
    }
}

使用import static 导入包中的静态方法和字段

import static java.lang.Math.*;

public class Date {
    public static void main(String[] args) {
        System.out.println(sqrt(100));   // 100的平方根
        System.out.println(max(10,100)); // 10和100之间最大值
        System.out.println(min(10,100)); // 10和100之间最小值
       
    }
}

运行结果

10.0
100
10

包在定义时,需要尽量指定成唯一的名字

常见的包:

  1. java.lang:系统常用基础类(String、Object),从JDK1.1后自动导入。
  2. java.lang.reflect:java 反射编程包;
  3. java.net:进行网络编程开发包。
  4. java.sql:进行数据库开发的支持包。
  5. java.util:是java提供的工具程序包。(集合类等) 非常重要
  6. java.io:I/O编程开发包。

七、static成员

例如,在学生类中,学生的姓名,年龄等信息是具体描述一个学生的,而上课的教室并不是描述学生的,所以教室是静态成员变量。

static修饰成员变量

static修饰的成员变量,成为静态成员变量

  • 不属于某个具体的对象,是所有对象所共享的
  • 可以通过对象访问,也可以通过类名访问(推荐)
  • JDK7及其以前,HotSpot(Java虚拟机)中存储在方法区(Java虚拟机不止有HotSpot),JDK8后,类变量存储在Java堆中
    随类的加载而创建,随类的卸载而销毁(JVM将类加载到其内部之后,类实际也是一个对象)
  public class Student {
        public String name;  // 姓名
        public String gender;  // 性别
        public String id;   // 学号
        public short age;  // 年龄      
        public static String classRoom = "f306";  // 就地初始化

        public static void main(String[]args) {
            Student s1 = new Student();  // 通过new实例化对象
           
            //通过类名访问静态成员变量
            System.out.println(Student.classRoom);
            
            //通过对象访问静态成员变量
            System.out.println(s1.classRoom);


        }
    }

static修饰成员方法

static修饰成员方法
若 Student 类中 classRoom 为 private 类,则在另外一个类StudentTest 中无法通过类名访问,则可以在 Student 类中添加一个public 静态方法

public static String getClassRoom(){
       return classRoom;
 }

1、被static修饰的成员方法成为静态成员方法,是类方法,不是某个对象所特有的
2、 可以通过对象调用,也可以通过类名.静态方法(…)调用(推荐)
3、静态方法没有隐藏的this引用参数,所以不能在静态方法中访问任何非静态成员变量
4、静态方法中不能调用任何非静态方法(原因:非静态方法中有this参数,在静态方法中调用时无法传递this引用)

//编译失败
public static String getClassRoom(){
 System.out.println(this); // 静态方法不能访问任何非静态
 return classRoom;
}

//编译失败
public static String getClassRoom(){
 age += 1;  //静态方法中不能访问实例变量
 return classRoom;
}

//编译失败
public static String getClassRoom(){
 doClass();  // 静态方法中不能访问实例方法
 return classRoom;
}

八、代码块

代码块:使用{ }定义的一段代码

分为普通代码块、构造块、静态块、同步代码块(多线程部分)

普通代码块

public class Main {
    public static void main(String[] args) {

        // 直接使用{}在方法中定义
        {
            int a = 10;
            System.out.println(a);
        }

    }
}

构造代码块

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

 public class Student {
        public String name;  // 姓名
        public String gender;  // 性别
        public String id;   // 学号
        private static String classRoom = "f306";
       

        // 实例代码块
        {
            this.name = "蓝胖子";
            this.gender = "女";
            this.id = "28256";
            System.out.println("姓名: " + name + " 性别: " + gender + " id: " + id);

        }


        public static void main(String[] args) {
            Student s1 = new Student(); 

            //通过类名访问静态成员变量
            System.out.println(Student.classRoom);
            //通过对象访问静态成员变量
            System.out.println(s1.classRoom);

        }
    }

运行结果

姓名: 蓝胖子 性别: 女 id: 28256
f306
f306

创建对象的时候,实例代码块会执行,每创建一个对象,实例代码块就执行一次。且实例代码块优先于构造方法执行(原因:编译完成后,编译器会将实例代码块中的代码拷贝到每个构造方法[用户所写]的第一条语句前)

静态代码块

被 static 定义的代码块称为静态代码块,一般用于初始化静态成员变量,在类加载阶段执行

 public class Student {
        private String name;  // 姓名
        private String gender;  // 性别
        private String id;   // 学号
        private static String classRoom ;

   //静态代码块
        static {
            classRoom = "f305";
            System.out.println("静态代码块");
        }


        public static void main(String[] args) {
            Student s1 = new Student();  // 通过new实例化对象
            Student s2 = new Student();
        }
    }

运行结果

静态代码块

1、静态代码块不管构造多少个对象,只会执行一次
2、如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次合并,最终放在生成的<>方法中,该方法在类加载时调用,并且只调用一次。

public class Demo {

    {
        System.out.println("实例代码块1");
    }

    {
        System.out.println("实例代码块2");
    }

    static{
        System.out.println("静态代码块1");
    }

    static{
        System.out.println("静态代码块2");
    }

    public static void main(String[] args) {
        Demo d1 = new Demo();
        Demo d2 = new Demo();
    }

}

运行结果

静态代码块1
静态代码块2
实例代码块1
实例代码块2
实例代码块1
实例代码块2

构造了两个对象,但只执行了一次

九、内部类

内部类:将一个类定义在另一个类的内部(也是封装的一个体现)
外部类:将一个类定义在一个方法内部

public class Demo {
    class InnerClass{
        
    }

}

Demo 是外部类, InnerClass 为内部类。
注意:Java的一个源文件中可以存放多个类,但不能成为内部类,最多只能有一个被 public 修饰,如下

public class Demo {
    
}


class Test{
    
}

内部类和外部类都有自己的字节码文件。

内部类的分类

public class Demo {

    //成员内部类,分为普通内部类和静态内部类
    //普通内部类
    class InnerClass1{

    }

    //静态内部类
    static class InnerClass2{

    }

    
    //在方法中定义内部类,统一称为局部内部类
    //实例代码块中
    {
        class InnerClass3{

        }
    }

    //静态代码块中
    static{
        class InnerClass4{

        }
    }

    //方法中定义内部类
    public void method(){
        class InnerClass5{
            
        }
        
        //普通代码块中定义内部类
        {
            class InnerClass6{
                
            }
        }
        
        
    }

}

普通内部类

在同一个类中访问

public class TestClass {


    int a;
    public void methodA(){

    }

    //普通内部类
    public class InnerClass{
        int b;
        void methodB(){

        }

    }


    public static void main(String[] args) {
        //普通类:成员使用,先构造对象,通过对象访问其成员
        TestClass ti = new TestClass();
        ti.methodA();

        //使用成员内部类中的普通内部类
        //借助外部类的对象创建内部类的对象
        InnerClass ic = ti.new InnerClass();
        ic.methodB();

    }

}

在同一个包,不同类中访问

void func(){
        TestClass ti = new TestClass();

        //实例化TestClass中内部类的对象
        TestClass.InnerClass tii = ti.new InnerClass();
    }

在一个内部类中可以直接使用外部类的方法

public class TestClass {


    int a;
    int b;
    public void methodA(){

    }

    //普通内部类
    public class InnerClass{
        int b;    // 编译器会给内部类增加一个引用类型的变量 TestClass this$0;用来指向外部类的对象
        void methodB(){
            a = 10;
            methodA();//可以引用外部变量和方法

            b = 20;//外部和内部都定义了b,给内部类自己的b赋值,就近原则
            TestClass.this.b = 30;//给外部的b赋值

        }

    }


}

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

静态内部类

访问同一个类中静态内部类

public class TestStaticClass {

    int a;
    int b;
    static int c;

    void methodA(){
        System.out.println("methodA()");
    }

    static class InnerClass{
        int d;
        static int e;

        void methodC(){

        }
    }

    public static void main(String[] args) {
        //静态成员变量访问
        System.out.println(TestStaticClass.c);

        //静态内部类对象的创建
        //不需要借助外部类对象进行创建
        InnerClass ic = new InnerClass();

    }


}

访问同一个包,不同类中的静态内部类

 //静态内部类
    
    public void MethodA(){
        //静态成员变量
        System.out.println(TestStaticClass.c);

    }

    //静态内部类对象
    //可以直接创建,不需要依赖外部类对象
    public static void main(String[] args) {
        TestStaticClass.InnerClass tic = new TestStaticClass.InnerClass();
    }

在静态内部类中不能直接访问外部类中的实例变量

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

十、对象的打印

public class Person {

    private String name;
    private String gender;
    private int age;

    //Alt+Insert--constructor--Ctrl多选会自动生成
    public Person(String name, String gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    //私有成员需要提供set\get方法
    //Alt+Insert--set/get--Ctrl多选会自动生成
    public void setAge(){
        this.age = age;
    }

    public int getAge(){
        return age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static void main(String[] args) {

        Person p = new Person("蓝胖子","女",18);
        System.out.println(p);
    }
}
 

运行结果

note20220327.Person@1540e19d

打印的地址,并未打印对象的值
如果要打印对象的值,需要重写 toString 方法。

  //Alt+Insert--toString会自动生成
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                '}';
    }

    public static void main(String[] args) {

        Person p = new Person("蓝胖子","女",18);
        System.out.println(p);
    }

运行结果

Person{name='蓝胖子', gender='女', age=18}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值