封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将 数据 与操作数据的 源代码 进行有机的结合,形成"类",其中数据和函数都是类的成员。
Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,更符合人类对事物的认
知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:
比如:
public:可以理解为一个人的外貌特征,谁都可以看得到
default: 对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了
private:只有自己知道,其他人都不知道
【说明】
protected主要是用在继承中,继承部分详细介绍
default权限指:什么都不写时的默认权限
访问权限除了可以限定类中成员的可见性,也可以控制类的可见性
class Computer {private String cpu; // cpuprivate String memory; // 内存public String screen; // 屏幕String brand; // 品牌---->default属性public Computer(String brand, String cpu, String memory, String screen) {this.brand = brand;this.cpu = cpu;this.memory = memory;this.screen = screen;}public void Boot(){System.out.println("开机~~~");}public void PowerOff(){System.out.println("关机~~~");}public void SurfInternet(){System.out.println("上网~~~");}
}
public class TestComputer {public static void main(String[] args) {Computer p = new Computer("HW", "i7", "8G", "13*14");System.out.println(p.brand); // default属性:只能被本包中类访问System.out.println(p.screen); // public属性: 可以任何其他类访问
// System.out.println(p.cpu); // private属性:只能在Computer类中访问,不能被其他类访问}
}
一般情况下成员变量设置成private,成员方法设置成public
在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。有点类似于目录。比如:为了更好的管理电脑中的歌曲,一种好的方式就是将相同属性的歌曲放在相同文件下,也可以对某个文件夹下的音乐进行更详细的分类。
在Java中也引入了包,包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,比如:一个包中的类不想被其他包中的类使用。包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。
Java 中已经提供了很多现成的类供我们使用. 例如Date类:可以使用 java.util.Date 导入 java.util 这个包中的 Date类
public class Test {public static void main(String[] args) {java.util.Date date = new java.util.Date();// 得到一个毫秒级别的时间戳System.out.println(date.getTime());}
}
但是这种写法比较麻烦一些, 可以使用 import语句导入包.
import java.util.Date;
public class Test {public static void main(String[] args) {Date date = new Date();// 得到一个毫秒级别的时间戳System.out.println(date.getTime());}
}
如果需要使用 java.util 中的其他类, 可以使用 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 都匹配
在这种情况下需要使用完整的类名
可以使用import static导入包中静态的方法和字段。
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);}
}
注意事项: import 和 C++ 的 #include 差别很大. C++ 必须 #include 来引入其他文件内容, 但是 Java 不需要.import 只是为了写代码的时候更方便. import 更类似于 C++ 的 namespace 和 using
基本规则
定义一个学生类
public class Student {public String name;public String gender;public int age;public double score;public Student(String name, String gender, int age, double score) {this.name = name;this.gender = gender;this.age = age;this.score = score;}public void DoClass(){}public void DoHomework(){System.out.println(this.name + "正在做作业");}public void Exam(){System.out.println(this.name + "正在做测验");}public static void main(String[] args) {Student s1 = new Student("Li leilei", "男", 18, 3.8);Student s2 = new Student("Han MeiMei", "女", 19, 4.0);Student s3 = new Student("Jim", "男", 18, 2.6);}
}
假设三个同学是同一个班的,那么他们上课肯定是在同一个教室,那既然在同一个教室,那能否给类中再加一个成员变量,来保存同学上课时的教室呢?答案是不行的。
之前在Student类中定义的成员变量,每个对象中都会包含一份(称之为实例变量),因为需要使用这些信息来描述具体的学生。而现在要表示学生上课的教室,这个教室的属性并不需要每个学生对象中都存储一份,而是需要让所有的学生来共享。在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对象,是所有对象所共享的。
static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。
【静态成员变量特性】
public static int classroom = 301;
一般类中的数据成员都设置为private,而成员方法设置为public,那设置之后,Student类中classRoom属性如何在类外访问呢
Java中**,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。**静态成员一般是通过静态方法来访问的。
【静态方法特性】
注意:静态成员变量一般不会放在构造方法中来初始化,构造方法中初始化的是与对象相关的实例属性
静态成员变量的初始化分为两种:就地初始化 和 静态代码块初始化。
就地初始化指的是:在定义时直接给出初始值
public class Student{private String name;private String gender;private int age;private double score;private static String classRoom = "Bit306"; // ...
}
使用 {} 定义的一段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:
普通代码块
构造块
静态块
同步代码块(后续讲解多线程部分再谈)
普通代码块:定义在方法中的代码块
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
这种用法较少见
构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。
Student
public class Student {private String name;private String gender;private int age;private double score;private static int classroom = 301;public Student() {System.out.println("I am Student init()!");}{this.name = "bit";this.age = 12;this.gender = "man";System.out.println("I am instance init()!");}public void DoClass(){}public void DoHomework(){System.out.println(this.name + "正在做作业");}public void Exam(){System.out.println(this.name + "正在做测验");}
}
testDemo
public class testDemo1 {public static void main(String[] args) {Student s1 = new Student();}
}
这里先执行构造代码块在执行构造方法
使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量
Student
public class Student {private String name;private String gender;private int age;private double score;private static int classroom = 301;public Student() {System.out.println("I am Student init()!");}{this.name = "bit";this.age = 12;this.gender = "man";System.out.println("I am instance init()!");}// 静态代码块static {classroom = 306;System.out.println("I am static init()!");}public void DoClass(){}public void DoHomework(){System.out.println(this.name + "正在做作业");}public void Exam(){System.out.println(this.name + "正在做测验");}
}
testDemo1
public class testDemo1 {public static void main(String[] args) {Student s1 = new Student();Student s2 = new Student();}
}
我们可以发现 我们创建了两个对象 实例代码块和构造方法都被调用了两次 但是静态代码块只被调用了一次
注意事项
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("Jim","男", 18);System.out.println(person);}
}
如果想要默认打印对象中的属性该如何处理呢?答案:重写toString方法即可。
要想知道原因就得看println是如何实现的
这里可以看到tostring是返回值是一串拼接起来的内容 我们只需要改写为自己想要的就可以
举个例子
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 String toString(){return "[" + this.name + "," + this.gender + "," + this.age + "]";}//重写了toString方法public static void main(String[] args) {Person person = new Person("Jim","男", 18);System.out.println(person);}
}