类和对象(补充)

本文详细介绍了Java中的包、导入、访问权限、静态导入、protected关键字、代码块以及内部类的概念和用法。讲解了如何组织类、访问控制、静态和非静态成员的使用,以及内部类的四种类型,包括静态内部类、匿名内部类等。此外,还讨论了类和对象的内存布局,局部变量和方法栈帧的区别。内容覆盖了Java面向对象编程的基础和核心知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

定义

包 (package) 是组织类的一种方式.
使用包的主要目的是保证类的唯一性.
概念图:
在这里插入图片描述

导入包中的类

Java 中已经提供了很多现成的类供我们使用
举例:

import java.util.Date;
public class Test {
    public static void main(String[] args) {
        Date date = new Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
   }
}

有一个万能的导包方式,一般都可以使用import java.util.*;

import java.util.*;
public class Test {
    public static void main(String[] args) {
        Date date = new Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
   }
}

但是有的时候会出现冲突,情况不多,这种是=时候要用完整的类名。
举例:

import java.util.*;
import java.sql.*;
public class Test {
    public static void main(String[] args) {
        // util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错
        Date date = new Date();
        System.out.println(date.getTime());
   }
}
// 编译出错
Error:(5, 9) java:Date的引用不明确
  java.sql 中的类 java.sql.Date 和 java.util 中的类 java.util.Date 都匹配

在这里插入图片描述
常见系统包
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编程开发包。

静态导入

使用 import static 可以导入包中的静态的方法和字段。
举例:

import static java.lang.System.*;
public class Test {
    public static void main(String[] args) {
        out.println("hello");
   }
}

使用这种方式可以更方便的写一些代码, 例如:

import static java.lang.Math.*;
public class Test {
    public static void main(String[] args) {
        double x = 30;
        double y = 40;
        // 静态导入的方式写起来更方便一些. 
        // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
        double result = sqrt(pow(x, 2) + pow(y, 2));
        System.out.println(result);
   }
}

包的访问权限

我们已经了解了类中的 public 和 private. private 中的成员只能被类的内部使用.
如果某个成员不包含 public 和 private 关键字, 此时这个成员可以在包内部其他类使用, 但是不能在包外部的类使用.
举个例子:
Demo1和Demo2在一个包中,Test在另一个包中。

package com.bit.demo;
public class Demo1 {
    int value = 0; }
package com.bit.demo;
public class Demo2 {
    public static void Main(String[] args) {
   Demo1 demo = new Demo1();
        System.out.println(demo.value);
   }
}
// 执行结果, 能够访问到 value 变量
10
import com.bit.demo.Demo1;
public class Test {
    public static void main(String[] args) {
        Demo1 demo = new Demo1();
        System.out.println(demo.value);
   }
}
// 编译出错
Error:(6, 32) java: value在com.bit.demo.Demo1中不是公共的; 无法从外部程序包中对其进行访
问

在这里插入图片描述

protected 关键字

如果把字段设为 private, 子类不能访问. 但是设成 public, 又违背了我们 “封装” 的初衷.两全其美的办法就是 protected 关键字。
对于类的调用者来说, protected 修饰的字段和方法是不能访问的
对于类的 子类 和 同一个包的其他类 来说, protected 修饰的字段和方法是可以访问的
举例:

// Animal.java
public class Animal {
    protected String name;
    public Animal(String name) {
        this.name = name;
   }
    public void eat(String food) {
        System.out.println(this.name + "正在吃" + food);
   }
}
// Bird.java
public class Bird extends Animal {
    public Bird(String name) {
        super(name);
   }
    public void fly() {
        // 对于父类的 protected 字段, 子类可以正确访问
        System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
   }
}
// Test.java 和 Animal.java 不在同一个 包 之中了. 
public class Test {
    public static void main(String[] args) {
        Animal animal = new Animal("小动物");
        System.out.println(animal.name); // 此时编译出错, 无法访问 name
   }
}

小结:
Java 中对于字段和方法共有四种访问权限
private: 类内部能访问, 类外部不能访问
默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
public : 类内部和类的调用者都能访问

代码块

定义

使用 {} 定义的一段代码.
根据代码块定义的位置以及关键字,又可分为以下四种:
普通代码块
构造块
静态块
同步代码块

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

public class Main{
 public static void main(String[] args) {
 { //直接使用{}定义,普通方法块
 int x = 10 ;
 System.out.println("x1 = " +x);
 }
 int x = 100 ;
 System.out.println("x2 = " +x);
 }
}
// 执行结果
x1 = 10
x2 = 100

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

class Person{ 
 private String name;//实例成员变量
 private  int age;
 private String sex;     
 public Person() {
 System.out.println("I am Person init()!");
 }   
 //实例代码块
 {
 this.name = "bit";
 this.age = 12;
 this.sex = "man";
        System.out.println("I am instance init()!");
 } 
 public void show(){
 System.out.println("name: "+name+" age: "+age+" sex: "+sex);
 } 
}
public class Main {
 public static void main(String[] args) {
 Person p1 = new Person();
 p1.show();
 }
 }
// 运行结果
I am instance init()! I am Person init()!
name: bit age: 12 sex: man

注意:实例代码块优先于构造函数执行
静态代码块:使用static定义的代码块。一般用于初始化静态成员属性

class Person{
 private String name;//实例成员变量
 private  int age;
 private String sex;
 private static int count = 0;//静态成员变量   由类共享数据 方法区
 
 public Person(){
 System.out.println("I am Person init()!");
 }
     //实例代码块
 {
 this.name = "bit";
 this.age = 12;
 this.sex = "man";
        System.out.println("I am instance init()!");
 }
 //静态代码块
 static {
 count = 10;//只能访问静态数据成员
        System.out.println("I am static init()!");
 }
 public void show(){
 System.out.println("name: "+name+" age: "+age+" sex: "+sex);
 }
}
public class Main {
 public static void main(String[] args) {
         Person p1 = new Person();
         Person p2 = new Person();//静态代码块是否还会被执行?
 }
}

注意
静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行

内部类

在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:静态内部类、匿名内部类、成员内部类和局部内部类。
定义在class 类名{}花括号外部的,即使是在一个文件里,也不是内部类了。
比如这样:

public class A{
    
}
class B{
    
}

静态内部类

public class Test {
    
    static class B{
   }
}

和静态变量、静态方法类似,静态内部类也是和当前类(Test)绑定。使用时,也是通过Test类来调用,如:

public class Test {
    
    static class B{
   }
    public static void main(String[] args) {
        B b1 = new Test.B();
        //在当前类Test中使用时,和静态变量,静态方法类似,也可以把Test.B()省略写为B()
        B b2 = new B();
   }
}

匿名内部类

匿名内部类的定义,是在一个方法或是代码块中定义的类,并且没有显示申明类的名称,比如这样:

public class Test {    
    public static void main(String[] args) {
        //定义了一个匿名内部类
        A a = new A(){
       };
   }
}
class A{ 
}

匿名内部类是使用的非常多的一种内部类,和A a = new A(); 这样的实例操作不同,后边还有一个大括
号,表示可以重写方法,其实是定义了另外一个类(没有显示的类名,所以叫匿名)。经常用在需要实例化某个对象,但需要重写方法时,比如new接口,抽象类就是使用匿名内部类较多的方式。

public class Test {
    public static void main(String[] args) {
        //定义了一个匿名内部类
        X x = new X(){
            @Override
            public void callback() {
           }
       };
   }
}
interface X{
    void callback();
}

类和对象的内存布局

局部变量和方法栈帧

public class Main{
    public static void swap(int a, int b){
        int tmp = a;
        a = b;
        b = tmp;
        System.out.printf("swap a=%d, b=%d%n", a, b);
   }
    public static void main(String[] args) {
        int a = 1;
        int b = 2;
        swap(a, b);
        System.out.printf("main a=%d, b=%d%n", a, b);
   }
}
//输出结果为
//swap a=2, b=1 main a=1, b=2

内存布局:对应程序的执行
在这里插入图片描述
整体看,某个方法进入时就有自己的方法栈帧,传入参数都是局部变量,方法退出后,所有栈帧内保存的局部变量就销毁了。

类和类变量

public class Main{
    private static int COUNT;
    public static void add(){
        COUNT++;
   }
    public static void main(String[] args) {
        add();
        System.out.println(A.COUNT);
   }
}
class A{
    static int COUNT; }

在这里插入图片描述
对于类和类变量来说,一定要加载到类以后才会加载到方法区,并会进行初始化赋值。比如这里没有执行到A.COUNT时,A类不会加载到方法区。

对象和成员变量

public class Main{
    
    public static void main(String[] args) {
        Person p = new Person();
        p.name = "张三";
        p.age = 18;
        p.sex = "男";
   }
}
class Person{
    String name;
    int age;
    String sex = "女"; }

在这里插入图片描述
对象要在成员变量初始化赋值完成,构造方法调用执行初始化操作以后,才算创建完成。
对象存储在堆里边,成员变量存储在堆里边的对象中。如果是成员变量是引用类型,会指向引用的对
象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值