JavaSE语法之七:封装
文章目录
一、封装的概念
面向对象的三大特性:封装、继承、多态。
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互。
二、访问限定符
Java中通过类和访问权限来实现封装:
①类可以将数据及封装数据的方法结合在一起,更符合人类对事物的认知;
②访问权限用来控制方法或者字段能否直接在类外使用。
Java中提供了四种访问限定符:
其中:
- public:在哪都能用;
- protected:不同包中的子类可用,主要是用在继承中;
- default:也叫包访问权限,只能在同一包中使用;
- private:只能在当前类中可用;
- 一般情况下,成员变量设置为private,成员方法设置为public。
三、封装扩展之包
1. 包的概念
为了更好的管理类,把多个类收集在一起成为一组,称为软件包。
包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,比如:一个包中的类不想被其他包中的类使用。包还有一个重要的作用:在同一个工程中允许存在相同名称的类,只要处在不同的包中即可。
2. 导入包中的类
Java中已经提供了很多现成的类供我们使用,在使用之前需要导包。如Date类,有两种方式可以导入包中的类:
方法一:使用 java.utul.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.*
//import java.sql.*
//报错了因为,java.util下面有个Date,java.sql下面也有个Date,就造成了混乱,这个时候要进行手动导包
public static void main(String[] args){
Date date = new Date();
java.util.Date date1 = new java,util,date(); //手动导包
}
import不起作用就要手动导包!
3. 自定义包
【基本规则】
- 在文件的最上方加上一个package语句,指定该代码在哪个包中;
- 包名需要尽量指定成唯一的名字, 通常会用公司的域名的颠倒形式(例如 com.bit.demo1 );
- 包名要和代码路径相匹配. 例如创建 com.bit.demo1 的包, 那么会存在一个对应的路径 com/bit/demo1 来存储代码;
- 如果一个类没有 package 语句, 则该类被放到一个默认包中。
4. 常见的包
- java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入;
- java.lang.reflect:java 反射编程包;
- java.net:进行网络编程开发包;
- java.sql:进行数据库开发的支持包;
- java.util:是java提供的工具程序包。(集合类等) 非常重要;
- java.io:I/O编程开发包。
四、实现封装
类的封装,是指将对象的状态信息隐藏在对象的内部,不允许外部程序直接访问对象的内部信息,而是通过该类所提供的方法来实现对内部信息的操作访问。
【实现封装】
- 封装成员变量:
private int age;
- 封装成员方法:
private void func();
此时,这些就只能在它所在的类中被访问,如果外界想要访问私有属性,需要提供一些方法来进行访问。
【访问私有属性】
方法一:
用public修饰的公有方法:getXxx()(获取属性值)、setXxx()(设置属性值)。
class Person{
private String name;
private int age;
public void show() {
System.out.println(name+" "+age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Test {
public static void main(String[] args) {
Person p1 = new Person();
p1.setName("张三");
p1.setAge(20);
System.out.println(p1.getName());
p1.show();
}
}
方法二:
使用构造方法,构造方法可以在实例化对象的同时就为这个对象的属性进行赋值。
class Person{
//私有的属性
private String name;
private int age;
public void show() {
System.out.println(name+" "+age);
}
//无参构造方法
public Person() {
}
//有参构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Test {
public static void main(String[] args) {
Person p1 = new Person("张三",19);
Person p2 = new Person("妮妮",20);
Person p3 = new Person("hhh",22);
p1.show();
p2.show();
p3.show();
}
}
五、static成员
1. 再谈学生类成员变量
我们创建一个学生类,每个学生对象都有姓名、年龄、班级三种属性,其中每个学生的班级都是一样的。
class Student {
private String name;
private int age;
private String classroom; //上课的教室
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Test2 {
public static void main(String[] args) {
Student s1 = new Student("张三",20);
Student s2 = new Student("李四",21);
System.out.println("nkn");
}
}
通过上图debug的结果可以看到,在堆上,每个学生类对象里面都有name、age和classroom三个属性。
我们知道学生对象的班级是一个,所以就没有必要再多次赋值,就可以用到static来对班级进行赋值。
class Student {
private String name;
private int age;
private static String classroom = "二班"; //上课的教室
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Test2 {
public static void main(String[] args) {
Student s1 = new Student("张三",20);
Student s2 = new Student("李四",21);
System.out.println("nkn");
}
}
我们重新打断点,可以发现,堆里只有name和age两个属性,此时classroom在方法区内,并且classroom不属于Student类对象了,classroom不用创建对象便可调用。
【概述】
在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对
象,是所有对象所共享的。
静态的成员变量不属于对象,所以不用通过对象的引用来访问,直接可以通过类名来访问,静态的不依赖对象!
2. static修饰成员变量
成员变量:
① 静态成员变量,也叫类变量、类成员;
② 非静态成员变量,也叫普通成员变量。
class Student {
private String name;
private int age;
public static String classroom = "二班"; //上课的教室
}
public class Test2 {
public static void main(String[] args) {
System.out.println(Student.classroom); //用类名直接调用,不创建Student对象
}
//输出
二班
3. static修饰成员方法
class Student {
private String name;
private int age;
public static String classroom = "二班"; //上课的教室
public static void func() {
System.out.println("这是静态成员方法");
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Test2 {
public static void main(String[] args) {
Student.func();
同样的原理,所以当时我们学方法的时候,写自定义方法一定要加static。静态方法:
- 可以通过对象调用,也可以通过类名.静态方法名() 方式调用,更推荐后者。
- 在静态方法内部(main方法也是静态方法),不能直接调用非静态的方法。所有非静态方法,一定是通过创建对象,通过对象的引用来调用的。
- 在静态方法内部,不能直接使用非静态的数据成员。只要是非静态的数据成员,也都需要通过对象的引用才能调用。
- 静态方法里面是不能使用this的。
4. static成员变量初始化
注意:静态成员变量一般不会放在构造方法中来初始化,构造方法中初始化的是与对象相关的实例属性。
- 直接赋值
public static String classRoom = "107Java直播间";
- 默认初始化
public static String classRoom; //此时默认为 null
- 可以提供 get 和 set方法来进行初始化
public static void getSize() {
return size;
}
public static void setSize(int size) {
Student.size = size;
}
- 通过代码块进行赋值
六、代码块
1. 代码块概念及其分类
**使用 {} 定义的一段代码称为代码块。**根据代码块定义的位置以及关键字,又可分为以下四种:
- 普通代码块
- 构造块:也叫非静态代码块、实例代码块
- 静态块
- 同步代码块(JavaEE中讲多线程的部分再谈)
2. 普通代码块
定义在方法内部的代码块(不常用!)
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);
}
}
3. 构造代码块
就是非静态代码块,也叫实例代码块。
定义在类中方法外的代码块(不加修饰符),一般用于初始化实例成员变量。
public class Student{
//实例成员变量
private String name;
private String gender;
private int age;
private double score;
public Student() {
System.out.println("I am Student 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) {
Student stu = new Student();
stu.show();
}
}
// 运行结果
I am instance init()!
I am Student init()!
name: bit age: 12 sex: man
4. 静态代码块
使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量, 就是静态化静态的数据成员/提前准备一些数据。
public class Student{
private String name;
private String gender;
private int age;
private double score;
private static String classRoom;
//实例代码块
{
this.name = "bit";
this.age = 12;
this.gender = "man";
System.out.println("I am instance init()!");
}
// 静态代码块
static {
classRoom = "bit306";
System.out.println("I am static init()!");
}
public Student(){
System.out.println("I am Student init()!");
}
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
}
}
public class OutClass {
class InnerClass{
}
}
// OutClass是外部类
// InnerClass是内部类
【注意事项】
- 静态代码块不管生成多少个对象,其只会执行一次
- 静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
- 如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(合并)
- 实例代码块只有在创建对象时才会执行
七、对象的打印
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);
}
}
// 打印结果:practice.Person@1b6d3586 这里输出的是 包名.类名@地址值(这里是真实地址的一个哈希值,可近似的理解为是地址)
因为它调用 Object 这个类中默认的toString方法为:
所以会输出以上结果。
如果想要默认打印对象中的属性该如何处理呢?答案:重写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;
}
@Override
public String toString() {
return "[" + name + "," + gender + "," + age + "]";
}
public static void main(String[] args) {
Person person = new Person("Jim","男", 18);
System.out.println(person);
}
}
// 输出结果:[Jim,男,18]
【总结】
对于想输出一个对象引用的值的时候:
① 如果没有自己写一个toString方法,那么就会调用 Object 这个类的方法;
②如果写了,就调用自己的。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!