文章目录
注:一个 java 文件里最好只写一个类,本章为了方便讲解写在一起。
1. 封装
封装:对外隐藏类的实现细节,只提供接口进行访问,来操作封装好的成员变量和成员方法。如:在实现上使用 private 修饰成员变量和成员方法,
这就好像电脑主机一样,对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器,USB插孔等,让用户来和计算机进行交互,完成日常事务。但实际上:电脑真正工作的却是CPU、显卡、内存等一些硬件元件。
1. 被 private 修饰的成员变量和成员方法只能在当前类中使用。
可以看到在类外不能访问被 private 修饰的成员变量和成员方法,但是在本类中可以访问,如上在sleep() 和 doClass() 方法中可以访问 name。
2. 使用 set 和 get 方法分别对成员变量进行操作。
class Student {
private String name;
private int age;
public void doClass() {
System.out.println(this.name + "正在上课");
}
//getName() 拿到被 private 修饰的成员变量
public String getName() {
return name;
}
//setName() 给被 private 的成员变量赋值
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class TestDemo1 {
public static void main(String[] args) {
Student student1 = new Student();
student1.setName("张三");
System.out.println(student1.getName());
}
}
- setName() 给被 private 的成员变量赋值。
- getName() 拿到被 private 修饰的成员变量。
- 可以根据自己的需求写 get 和 set 方法。
- 当然也可以用构造方法对被 private 修饰的成员变量赋值。
2. 修饰访问限定符
NO | 范围 | private | default | protected | public |
---|---|---|---|---|---|
1 | 同一包中的同一类 | √ | √ | √ | √ |
2 | 同一包中的不同类中 | √ | √ | √ | |
3 | 不同包中的子类 | √ | √ | ||
4 | 不同包的非子类 | √ |
2.1 包的概念
- 为了更好的管理类,把多个类收集在一起成为一组,称为软件包。
- 包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,比如:一个包中的类不想被其他包中的类使用。包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。
其实一个包就是一个文件夹,我们可以在 src 包下创建一个 TestDemo1.java 文件。
所以在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。因为,不同文件夹中可以有相同名字的文件。
这时我们就可以解释之前我们使用 java 自带的工具类时需要导包了,就像使用别人的东西的时候,需要跟别人说一声。
import java.util.Arrays;//导入java包下util包下的Arrays类。这时我们就可以操作Arrays类了
public class Main {
public static void main() {
int[] array = {1, 2, 3};
int[] copy = Arrays.copyOf(array, array.length);
System.out.println(Arrays.toString(array));
System.out.priintln(Arrays.toString(copy));
}
}
导入java包下util包下的Arrays类。这时我们就可以操作Arrays类了
2.2 自定义包
包的名字全为小写,且是公司域名倒着写
如:
创建包:
我们在 demo1 包下再创建一个 Test1.java 文件。
一个java文件中如果没有 package 这个语句则代表它被放在 src 跟目录下。
2.3 private
private 访问限定符,在封装时我们说过,只能在当前类中访问 ,当想要访问被 private 修饰的成员变量时,需要提供 get 或 set 方法。
2.4 default (默认权限,什么都不写的时候)
default 为包访问权限,当成员变量或成员方法没有修饰访问限定符修饰的时候就是默认为包访问权限,只能在同一包下使用。
1. 在同一包中使用
如在demo1包下创建两个类,在 Test1 中的创建包访问权限成员变量和成员方法:
在 Test2 中访问 Test1 中的成员变量和成员方法
这里注意需要导包,可以看到没有报错我们运行看看
当然使用包访问权限也可以在本类中访问:
package com.boke.demo1;
public class Test1 {
//成员变量和成员方法前面不写修饰访问限定符
int a = 100;
void test() {
System.out.println("只能在同一包下使用");
}
public static void main(String[] args) {
Test1 test = new Test1(); //静态方法中不能直接访问非静态的方法,需要实例化访问
System.out.println(test.a);
}
}
2. 不能在不同包中使用
可以看到,在不同包中不能使用。
public
- 被 public 修饰的只要在该项目中都能访问。
protected
- 先不说,到继承在说。
3. static 关键字
当我们这样写时。
package com.boke.demo2;
class Student {
public String name;
public int age;
public String classes;
public Student(String name, int age, String classes) {
this.name = name;
this.age = age;
this.classes = classes;
}
}
public class Demo1 {
public static void main(String[] args) {
Student student1 = new Student("张三", 20, "2班");
Student student2 = new Student("小李", 18, "2班");
}
}
但当我们在教室前加个 static 关键字时
public static String classes;
对象中被 static 修饰的 classes 在对象中消失了。
在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对象,是所有对象所共享的。
因为它不属于某个具体的对象,是所有对象共享的,所以其不存在任何对象的内存中。
静态的成员变量和成员方法的访问:
class Student {
public String name;
public int age;
public static String classes;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//可在 toString() 方法中加如打印 classes
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", classes='" + classes + '\'' +
'}';
}
}
public class Demo1 {
public static void main(String[] args) {
Student student1 = new Student("张三", 20);
Student student2 = new Student("小李", 18);
//student1 和 student2 对象共享 classes 静态成员变量
Student.classes = "2班";//通过 类名.成员变量 访问。
System.out.println(student1);
System.out.println(student2);
}
}
可在 toString() 方法中加如打印 classes
classes 属于所有对象共有的,所以只需要赋一次值,之后的对象都可使用。
同时静态的方法也可以同过对象进行访问:
class Student {
public String name;
public int age;
public static String classes;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Demo1 {
public static void main(String[] args) {
Student student1 = new Student("张三", 20);
//通过对象引用进行访问
student1.classes = "2班";
System.out.println(student1.classes);
}
}
但是不建议这么些,我们再来看看以下写法:
class Student {
public String name;
public int age;
public static String classes;
}
public class Demo1 {
public static void main(String[] args) {
Student student1 = null;
//通过对象引用进行访问
student1.classes = "2班";
System.out.println(student1.classes);
}
}
我们这样看都以为它是错的,但是这样写是对的,因为静态成员不依赖于对象,当加载类时创建,是所有对象的共享成员。
静态成员变量 和 静态成员方法不依赖于任何对象,这句话很重要。
1. 普通的成员方法中,可以访问静态的成员变量/方法。
class Student {
public String name;
public int age;
public static String classes;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void doClass() {
System.out.println(this.name + "正在" + classes + "上课");
}
}
public class Demo1 {
public static void main(String[] args) {
Student student1 = new Student("张三", 20);
Student.classes = "503";
student1.doClass();
}
}
2. 静态成员方法中不能直接访问非静态成员变量和方法,因为静态的不依赖于对象,想要访问时,需要实例化对象后再进行访问
可以看到在静态方法中访问非静态成员变量没有同过实例化对象访问错误了。
通过以上学习我们也可以知道当时同一个类中写方法时为什么加 static 了
当我们不加时,则需要先实例化再进行访问。
4. 代码块
使用 {} 定义的一段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:
- 普通代码块
- 实例代码块
- 静态代码块
- 同步代码块
我们这里先介绍普通代码块、实例代码块和静态代码块
4.1 普通代码块
定义在方法中
4.2 实例代码块
实例代码块,优先执行于构造方法,一般用来初始化
class Cat {
public String name;
public int age;
//实例代码块
{
System.out.println("实例代码块,优先执行于构造方法,一般用来初始化");
}
public Cat() {
System.out.println("不带参数的构造方法");
}
}
public class Demo2 {
public static void main(String[] args) {
Cat cat1 = new Cat();
}
}
4.3 静态代码块
静态代码块,优先执行于实例代码块和构造方法,一般用于初始化,并且只执行一次
package com.boke.demo2;
class Cat {
public String name;
public int age;
//实例代码块
{
System.out.println("实例代码块,优先执行于构造方法,一般用来初始化");
}
//静态代码块
static {
System.out.println("静态代码块,优先执行于实例代码块和构造方法,一般用于初始化,并且只执行一次");
}
public Cat() {
System.out.println("不带参数的构造方法");
}
}
public class Demo2 {
public static void main(String[] args) {
Cat cat1 = new Cat();
System.out.println("------------------");
Cat cat2 = new Cat();
}
}
可以看到静态代码块只执行一次,当实例化 cat2 对象后,静态代码块不执行了。
5. 内部类
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。在Java 中,可以将一个类定义在另一个类,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。
5.1 实例内部类
1. 如何写实例内部类:
当然我们没写构造方法时,编译器还是会默认帮我们写一个不带参数的构造方法。
2. 如何实例化内部类
实例内部类实际上是和实例成员变量的等级是一样的。注:普通的成员变量/方法又叫实例成员变量/方法。
相当于一个变量的定义 :int a = 10;
外部类名.内部类名是一个类型 想要 new 一个对象,需要拿到此类,因为它是内部类,和外部类的成员是同一等级的,所以需要先实例化外部类对象,再通过 外部类对象引用. 进行访问。相当于你想在外部类外访问外部类的成员变量,需要先实例化对象,再使用 对象引用.成员变量 进行访问。
class OuterClass {
private int data1 = 10;
public int data2 = 20;
public static int data3 = 30;
//实例内部类
class InnerClass {
public int data4 = 40;
private int data5 = 50;
public InnerClass() {
System.out.println("实例内部类的构造方法");
}
}
}
public class TestDemo1 {
public static void main(String[] args) {
//第一种方法
OuterClass.InnerClass innerClass1 = new OuterClass().new InnerClass();
//第二种方法
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass2 = outerClass.new InnerClass();
}
}
3.实例内部类不能定义静态成员变量,如果定义了需要在 static 关键字后加上 final。并且实例内部类不能定义静态的成员方法。
加上 final 后
不过被 final 修饰过的变量不能修改值:
可通过 类型.静态成员变量 访问:
4. 实例内部类访问外部类的成员。
4.1 当外部类成员变量和内部类成员变量名字不一样时
4.2 当外部类成员变量和内部类成员变量名字一样时:
class OuterClass {
private int data1 = 10;
public int data2 = 20;
public static int data3 = 30;
//实例内部类
class InnerClass {
public int data1 = 40;
private int data5 = 50;
public static final int data6 = 100;
public InnerClass() {
System.out.println("实例内部类的构造方法");
}
public void method() {
System.out.println(data1);
}
}
}
public class TestDemo1 {
public static void main(String[] args) {
//第一种方法
OuterClass.InnerClass innerClass1 = new OuterClass().new InnerClass();
innerClass1.method();
}
}
可以看到优先访问自己的
当外部类成员变量和内部类成员变量名字一样时,这时我们在内部类中访问自己的内部类成员变量最好加上 this. 区分开
那么我们该如何取到外部类的成员变量呢?
5. 外部类如何访问实例内部类
在外部类中实例化内部类,并且在外部类中可以访问内部类中被 private 修饰的成员变量
最后,在上面的代码中编译后产生的字节码文件有几个呢?
总结:
- 外部类中的任何成员都可以被在实例内部类方法中直接访问。
- 实例内部类所处的成员与外部类成员位置相同,因此也受public、private等访问限定符的约束
- 在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外部类名称.this.同名成员 来访问
- 实例内部类对象必须在先有外部类对象前提下才能创建
- 实例内部类的非静态方法中包含了一个指向外部类对象的引用
- 外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建外部类的对象。
5.2 静态内部类
被static修饰的内部成员类称为静态内部类。
1. 如何实例化静态内部类
我们知道静态的是不依赖于对象的,直接通过类型(类名)进行访问。
class OuterClass1{
public int data1 = 10;
private int data2 = 20;
public static int data4 = 30;
//静态内部类
static class InnerClass1{
public int data4 = 40;
private int data5 = 50;
public static int data6 = 60;
}
}
public class TestDemo2 {
//不依赖于对象
OuterClass1.InnerClass1 innerClass = new OuterClass1.InnerClass1();
}
2. 静态内部类只能访问外部类的静态成员变量/方法,如果要访问外部类的非静态成员变量/方法,需要提供外部类的对象。
2.1 静态内部类访问外部类的静态成员变量
2.2 静态内部类访问外部类非静态的成员变量
class OuterClass1{
public int data1 = 10;
private int data2 = 20;
public static int data4 = 30;
//静态内部类
static class InnerClass1{
public int data4 = 40;
private int data5 = 50;
public static int data6 = 60;
public void method() {
//需要先创建外部类对象,然后访问
OuterClass1 outer = new OuterClass1();
System.out.println(outer.data1);
}
}
}
public class TestDemo2 {
public static void main(String[] args) {
//不依赖于对象
OuterClass1.InnerClass1 innerClass = new OuterClass1.InnerClass1();
innerClass.method();
}
}
3. 外部类怎么访问静态内部类的成员变量/方法
外部类访问静态内部类的成员变量级方法需要提供静态内部类的对象。
好的,到这里本章节就结束了,如发现有错误,请各位大佬及时指出
^_^