Java类与对象详解(3)
目录
封装
封装的概念
我们知道,面向对象程序的三大特性为:封装,继承,多态。而类和对象阶段,主要研究的是封装特性,何为封装呢?简单来说就是套壳屏蔽细节。在java语法中,就是指被private修饰的成员变量和成员方法。(private一会会详细介绍)。
那么为什么用private修饰了,我们就说实现了封装了呢?来看下面一个代码:
class Peo{
private int age;
private String name;
public Peo(){
}
public Peo(int age, String name){
this.age = age;
this.name = name;
}
public void sleep(String name){
System.out.println(this.name + "正在睡觉");
}
}
public class test1 {
public static void main(String[] args) {
Peo p = new Peo();
//直接调用?
p.name = "马牛逼";
}
}
这里出现了一个错误:
原因是这里Peo类中name被private 修饰了(等同于name被屏蔽了,用户不知道这个p对象中的属性),所以不能直接调用name。通俗的来说:就是p这个对象具有隐私权,根据宪法(private),我们无法侵犯它的隐私(name这个属性)。
访问限定符
Java中主要通过类和访问权限进行封装:类可以将数据以及封装数据的方法结合到一起,更符合人类对事物的认知,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:
比如:
public:可以理解为一个人的外貌特征,谁都可以看得到。
default:对于自己家族中(同一个包中)不是什么秘密,对于其他人就是隐私了(默认权限)
private:只有自己知道,其他人都不知道。
说明:
protected主要用在继承中,继承部分会详细介绍
default权限指:前面不写访问限定符的默认权限
访问权限除了可以限定类中成员的可见性,也可以限制类的可见性
注意:一般情况下成员变量设置为private,成员方法设置为public.
封装扩展之包
包的概念
在面向对象体系中,提出了软件包的概念,即:为了更好地管理类,把多个类放在一起成为一组,称为软件包。有点类似于目录。比如管理电脑中歌曲的方式如下:
在Java中也引入了包,包是对类,接口等封装机制的体现,是一种对类或者接口等很好的组织方式,比如:一个包中的类不想被其他包中的类使用。包还有一个重要的作用:在一个工程中允许出现相同名称的类,只要在不同包中即可。
导入包中的类
Java中已经提供了很多现成的类供我们使用,例如Date类:可以使用java.util.Date导入java.util这个包中的Date类。
public class test2 {
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 test2 {
public static void main(String[] args) {
Date date = new Date();
//得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
如果要使用java.util中的其它类,可以使用import java.util.*;
但是还是更建议显式地指定导入java.util的其它类。否则可能会出现冲突的情况,举个栗子:
import java.util.*;
import java.sql.*;
public class test2 {
public static void main(String[] args) {
Date date = new Date();
//得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}
这里有这样的问题:
因此这种情况应该使用完整的类名。
可以用import static 导入包中的静态方法和字段。eg:
import static java.lang.Math.*;
public class test3 {
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);
}
}
自定义包
基本规则
1.在文件的最右上方加上一个package语句指定该代码在哪个包中。
2.包名需要尽量指定生成唯一的名字,通常会用公司域名的颠倒形式(eg:com.air.demo)
3.包名要和代码路径相匹配,例如创建com.air.demo的包,那么就会存在一个对应路径com/air/demo来存储代码
4.如果没有package的语句,则该类被放在一个默认包中。
包的访问权限控制举例
Computer位于Demo1中,TestComputer位于Demo2中
package Demo1;
public class Computer {
private String cpu;//cpu
private String memory;//内存
public String screen;//屏幕
String brand;//品牌
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("上网---");
}
}
package Demo2;
import Demo1.Computer;
public class TestComputer {
public static void main(String[] args) {
Computer p = new Computer("MAC","M1", "8G", "13*14");
System.out.println(p.screen);
//System.out.println(p.cpu);//报错:cpu是私有的,不允许被其它类访问
//System.out.println(p.brand);//报错:brand是default,不允许被其他的包访问
}
}
//注:如果去掉Computer类之前的public 修饰符,代码也会编译失败
常见的包
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 修饰的成员变量呢?
static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。(比如创建几个学生对象,他们都是一班的,那么这个班级是共享的,是static 修饰的成员变量)。
静态成员变量的特性
1.不属于某个具体的对象,是类的属性,为所有对象共享的,不存储在某个对象的空间中
2.既可以通过对象访问,也可以通过类名访问,但一般更推荐类名访问
3.类变量存储在方法区中
4.生命周期伴随着类的一生(即:随类的加载而创建,随类的销毁而卸载)
举个栗子:
public class Student {
public String name;
public String gender;
public int age;
public double score;
public static String classroom = "303";
public static void main(String[] args) {
//静态变量可以直接通过类名来访问
System.out.println(Student.classroom);
Student s1 = new Student();
Student s2 = new Student();
//也可通过类名来访问,不过classroom是两个对象共享的
System.out.println(s1.classroom);
System.out.println(s2.classroom);
}
}
通过调试,在监视窗口可以看到,静态成员并没有存储到某个具体的对象中。
static修饰成员方法
一般类中的数据成员都设置为private,而成员方法设置为public,那设置之后,Student类中classRoom属性如何在类外访问呢?
class Student {
private String name;
private String gender;
private int age;
private double score;
private static String classRoom = "103";
}
public class TestStudent{
public static void main(String[] args) {
System.out.println(Student.classRoom);
}
}
//java: classRoom 在 Demo2.Student 中是 private 访问控制
那static 属性应该如何访问呢?
Java中,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。(把静态变量叫做类变量/方法)静态成员一般是通过静态方法来访问的。
举个栗子:
public class Student {
private static String classRoom = "103";
public static String getClassRoom() {
return classRoom;
}
public static void main(String[] args) {
System.out.println(Student.classRoom);
}
}
显而易见静态方法可以轻松解决问题,下面我们来说一下静态方法的特性:
1.与静态成员变量相同,不属于某个具体的对象,属于类
2.可以通过对象调用,也可以通过类名.静态方法名的方式调用,更推荐后者
3.不能在静态方法中使用任何非静态变量
4.静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中不能传递this引用
static 成员变量的初始化
注意:静态变量一般不在构造方法中初始化,因为静态变量不属于任何对象,构造方法中初始化的是对象相关的实例属性。
静态成员变量的初始化分为两种:就地初始化和代码块初始化。
1.就地初始化:在定义时直接给出初始值。
2.静态代码块初始化:见下文:
代码块
代码块的概念及其分类
使用{}定义的一段代码成为代码块。根据代码块的定义位置以及关键字,又可分为以下四种:
1.普通代码块
2.构造块
3.静态块
4.同步代码块
普通代码块
定义:定义在方法内的代码块
public class Test1 {
public static void main(String[] args) {
{//直接用{}定义普通代码块
int x = 10;
System.out.println(x);
}
int x = 100;
System.out.println(x);
}
}
这种用法偏少
构造代码块
构造块:定义在类中的代码块(不加修饰符) 。也叫:实例代码块
构造代码块一般适用于初始化实例成员变量。
class Student1 {
//实例成员变量
private String name;
private String gender;
private int age;
private double score;
//构造方法
public Student1() {
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 show(){
System.out.println("name:" + name +",age:" + age + ",gender:" + gender);
}
public static void main(String[] args) {
Student1 stu = new Student1();
stu.show();
}
}
静态代码块
使用static 定义的代码块称为静态代码块。一般用于初始化静态成员变量。、
public class Student2 {
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 = "103";
System.out.println("I am static init()");
}
//构造方法
public Student2(){
System.out.println("I am Student init()");
}
public static void main(String[] args) {
Student2 s1 = new Student2();
Student2 s2 = new Student2();
}
}
通过上面的代码我们可以总结出如下规律:
1.静态代码块不管实例化出多少对象,都只执行一次
2.(以只创建一个对象为例)执行代码块的基本顺序为:静态代码块->实例代码块->构造方法
3.静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
4.如果一个类中包含多个代码块/实例代码块,它们会合到一块
5.实例代码块只有创建了对象才会执行,而静态代码块不创建对象也可以