封装
- 封装(Encapsulation)是面向对象的三大特征之一(另外两个是继承和多态),它是的是对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
- 为了实现良好的封装,需要从两个方面考虑:
1.将对象的成员变量和实现细节隐藏起来,不允许外部直接访问
2.把方法暴露出来,让方法来控制对这些成员变量进行安全的访问和操作
- 对一个类或对象实现良好的封装,可以实现以下目的:
1.隐藏类的实现细节
2.让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里加入控制逻辑,限制对
成员变量的不合理访问
3.可进行数据检查,从而有利于保证对象信息的完整性。
4.便于修改,提高代码的可维护性。
- 权限访问控制符:
private(当前类访问权限)
default(包访问权限)
protected(子类访问权限):如果一个成员(包括成员变量、方法和构造器等)使用protected
类访问。在通过情况下,如果使用protected来修饰一个方法,通常是希望其子类来重写这个方
法。
public(公共访问权限)
- 关于访问控制符的使用,存在如下几条基本原则:
1.类里的绝大部分成员变量都应该使用private修饰,只有一些static 修饰的、类似全局变量
的成员变量,才可能考虑使用public修饰。除此之外,有些方法只用于辅助实现该类的其他方
法,这些方法被称为工具方法,工具方法也应该使用private修饰。
2.如果某个类主要用做其他类的父类,该类里包含的大部分方法可能仅希望被子类重写,而不想
被外界直接调用,则应该使用protected修饰这些方法。
3.希望暴露出来给其他类自由调用的方法应该使用public修饰。因此,类的构造器通过使用
public修饰,从此允许在其他地方创建该类的实例。因为外部类通常都希望被其他类自由使用,
所以大部分外部类都使用public修饰。
static关键字
-
有static修饰的成员属于类本身,没有static修饰属于该类的实例;有static修饰的成员属于类本身,没有static修饰属于该类的实例;
-
如果这个方法使用了static修饰,则这个方法属于这个类 如果这个方法使用了static修饰,则这个方法属于这个类
- 局部变量:形参 方法局部变量 代码块局部变量
- Java的实参值如何传入方法中:值传递
- 当系统加载类或创建该类的实例时,系统自动为成员变量分配内存空间,然后自动为成员制定初始值。
- 变量的使用的规则:
定义一个成员变量时,成员变量将被放置到堆内存中,成员变量的作用域将扩大到类存在范围或者对象存在范围,这种范围的扩大有两个害处:
增大了变量的生存时间,这将导致更大的内存开销。
扩大了变量的作用域,这不利于提高程序的内聚性。 - 当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值
byte short int :0
long:0L
float:0.0F
double:0.0
char:0或者写为:'\u000'(表现为空)
boolean:flase
引用类型:null
- 类的访问机制:
在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。
(例外:static方法访问非static,编译不通过。)
在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中定义的成员。
- Java默认为所有源文件导入java.lang包下的所有类,因此前面在Java程序中使用String
、System类时都无须使用import语句来导入这些类。但对于Arrays类,其位于java.util
包下,则必须使用import语句来导入该类。
- import语句导入的java.sql和java.util包下都包含都包含了Date类,系统无法分清。如果
需要制定包下的Date,则只能使用该类的全名。 java.sql.Date d = new java.sql.Date(); - 构造器最大的用处就是在创建对象时执行初始化。当创建一个对象时,系统为这个对象的实例
变量进行默认初始化,这种默认的初始化把所有基本类型的实例变量设为0或false,把所有引用 类型变量为null。
- 一旦程序员提供了自定义的构造器,系统就不再提供默认的构造器,因此不能再用new 类();
代码来创建实例,因此该类不再包含无参数的构造器。如果用户希望该类保留无参数的构造器,或者希望有多个初始化过程,则可以为该类提供多个构造器。如果一个类里提供了多个构造器,就形成了构造器的重载。
- 遇见同名且具有同样的参数的构造器 `
package CrazyJava;
//同名构造器且具有同样的参数
public class ConstructorOverload {
public String name;
public String color;
public int weight;
//2个参数的构造器
public ConstructorOverload(String name, String color){
this.name = name;
this.color = color;
}
//3个参数的构造器
public ConstructorOverload(String name, String color,int weight){
//通过this调用另一个重载的构造器的初始化代码
this(name , color);
//下面this引用该构造器正在初始化的Java对象
this.weight = weight;
}
}
包的作用:
1.包帮助管理大型软件:将语气相似的类组织到同一个包中。比如:MVC的设计模式
2.包可以包含类和子包,划分项目层次
3.解决类命名冲突的问题
4.控制访问权限
public类可以在任意地方被访问
default类只可以被同一个包内部的类访问
- 对象类型转换
对Java对象的强制类型转换成为造型
从子类到父类的类型转换可以自动进行
从父类到子类的类型转换必须通过造型(强制类型转换)实现
无继承关系的引用类型间的转换是非法的
在造型可以使用instanceof操作符测试一个对象的类型
Objcet类
- Object类:Object类是所有java类的根父类
Object类中的主要结构
- 引用类型比较引用(是否指向同一个对象):只有指向同一个对象时,==才返回 true.
- 当用equals()方法进行比较时,对类FIle、String、Date及包装类(Wrapper
Class)来说,是比较类型及类容而不考虑引用的是否是同一个对象。 在这些类中都重写了Obect类的equals()方法
- Object类-equals方法重写 Object对象中public boolean equals(Object
obj),指的是某个对象是否与对象“相等”。这里的相等。这里的相等指的是比较的两方指向同一个对象。
对于任何非空引用值x和y,当且仅当x和y引用同一个对象
关键字static
使用范围:在Java类中,可用static修饰属性、方法、代码块、内部类
被修饰后的成员具备以下特点:
1.随着类的加载而加载
2.优先于对象存在
3.修饰的成员,被所有对象所共享
4.访问权限允许时,可不创建对象,直接被类调用
包装类
Java系统加载并初始化某个类时,总是保证该类的所有父类(包括直接父类和间接父类)全部加载并初始化。
-
当JVM第一次主动使用某个类时,系统会在类准备阶段为该类的所有静态成员变量分配内存;在初始化阶段则负责初始化这些静态成员变量,初始化静态成员变量就是执行类初始化代码或者声明类成员变量时指定的初始值,它们的执行顺序与源代码中的排列顺序相同。
-
Java提供了final关键字来修饰变量、方法和类,系统不允许为final变量重新赋值,子类不允许覆盖父类的final方法,final类不能派生子。通过使用final关键字,允许Java实现不可变类,不可变类会使系统更加安全
abstract和interface两个关键字分别用于定义抽象类和接口
包装类型的变量是引用数据类型,但包装类的实例可以与数值类型的值进行比较
两个Integer类型数的比较
- 从java.lang.Integer类的源码可以看出:系统把一个-128-127之间的整数自动装箱成Integer实例,并放入了一个名为cache的数组中缓存起来。如果把一个-128-127之间的整数自动装箱成一个Integer实例时,实际上是直接指向对应的数组元素,因此-128-127之间的同一个整数自动装箱成Integer实例时,永远都是引用cache数组的同一个数组元素,所以它们相等;但每次把一个不在-128-127范围内的整数自动装箱成Integer实例时,系统总是重新创建一个Integer实例,所以出现程序中的运行结果。
- 无符号整数的最大特点是最高位不再被当成符号位,因此无符号整数不支持负数,其最小值为0.
- toString()方法时Object类里的一个实例方法,所有的Java类都是Object类的子类,因此所有的类都具有toString()方法;
toString()方法是一个非常特殊的方法,它是一个“自我描述”方法,该方法总是返回该对象实现类的“类名+@+hasCode”值
常量池专门用于管理在编译时被确定并被保存在已编译的.class文件中的一些数据,它包括了关于类、方法、接口中的变量,还包括字符串常量。
-
在进行String与其他类型数据的连接操作,自动调用toString()方法
-
基本数据类型转换为String类型时,调用了对应包类的toString()方法 int a =10;
System.out.println(“a=”+a);
下面程序示范了JVM使用常量池管理字符串直接量的情形
public class StringCompareTest{
public static void main(Strin[] args){
//s1直接引用常量池中的“疯狂Java”
String s1 = "疯狂Java";
String s2 = "疯狂";
String s3 = "Java";
//s4后面的字符串值可以在编译时就确定下来
//s4直接引用常量池中的“疯狂Java”
String s4 = "疯狂"+"Java";
//s5后面的字符串值可以在编译时就确定下来
//s5直接引用常量池中的“疯狂Java”
String s5 = "疯"+"狂"+"Java";
//s6后面的字符串值不能在编译时就确定下来
//不能引用常量池中的字符串
String s6 = s2+s3;
//使用new调用构造器会创建一个新的String对象
//s7引用堆内存中新创建的String对象
String s7 = new String("疯狂Java");
System.out.println(s1 == s4);//输出true
System.out.println(s1 == s5);//输出true
System.out.println(s1 == s6);//输出false
System.out.println(s1 == s7);//输出false
}
}