1.数组以句柄的方式来管理内存
2.方法的overload(面向对象的性质,以多态的形式)
只允许根据参数列表(参数类型、个数、顺序等)进行区分,那为什么不能根据返回值类型进行区分呢?
因为在调用方法时候,一定要能体现出来其特征。
封装、继承、多态
类的封装
类似于开车与汽车的原理
(1)把数据和方法紧密绑定在一起
(2)从外面看,仅知道一些接口,但不知道接口的具体如何操作
优点:隐藏细节
那么为什么要封装呢?
因为除了隐藏细节,更需要保证自身逻辑的完整性
一般需要定义成员变量(属性)和成员方法
private是私有成员,不能被外部类访问 ——隐藏信息
为了访问私有成员,需要定义public方法 ——封装
举个栗子:
比如这程序,未进行封装,取值超出了范围,未能保证逻辑完整性。
关于构造方法:
(1)名与所在类一致
(2)没有返回值类型
说明:如果没有定义,系统默认调用此方法
类在使用前,必须使用new()创建,public是可以通过实力对象存取,private对外部不可见。
上图程序,如果不定义则初始化能否调用?
否,因为在程序中还有其他构造函数,并不会调用系统默认的构造函数。
Static关键字:“静态”:分配的地址是固定不变得
定义一些与类无关的变量和方法时,使用static关键字
即使没有创建那个类的一个实例对象也可以调用一个static方法或者访问一个static变量
Static的变量或方法在程序初始化之前分配空间,而其他变量或方法在程序运行中动态分配空间。使用“类名.方法名”的方式可以直接调用static方法。比如 常用的Math类
例如:public static void main(String[] args) 虚拟机需要找到整个程序的入口点,如果因为main所在的class没有生成对象,导致main无效,那程序就无法启动了。
一些基本数据类型的封装类:
类的初值
(1)利用overload构造方法
(2)利用set、get方法
友谊成员
变量或者方法之前没有存取修饰字,则成为友谊成员或者套件存取,只能访问当前包
单例模式:在内存中只有一个实例
例如:
class Singleton{
private static Singleton instance;
private static Object Lock = new Object();
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized (Lock){
if(instance == null){
instance = new Singleton();
}
}
}
return instance ;
}
}
Singleton的特点是由类自己来保证实例的唯一性
类的继承
继承的思想:
先定义一个包含公用方法和公用变量的类做为父类,在此基础上建立具有专用方法和专用变量的的类作为子类,方便编程。
默认的父类为 Object类
继承能够体现出父类和子类对象的一种逻辑联系
父类的构造方法不能被继承,其private成员变量和成员方法不能被子类继承,虽然不能继承,但是在内存中依然存在,可以间接访问到。protected成员可以被子类访问。super表示“父类的”
说明:子类在继承父类后,其方法只能扩大所继承的范围,即 只能把protect改为public,不可以把protect改为private
举个栗子1:
public class Equals {
public static void main(String[] args) {
Integer n1 = new Integer(100);
Integer n2 = new Integer(100);
System.out.println(n1==n2);
System.out.println(n1.equals(n2));
}
}
输出结果为:
false
true
举个栗子2:
class Integer{
private int i;
public Integer(int i){
this.i = i;
}
}
public class Equals2 {
public static void main(String[] args) {
Integer n1 = new Integer(100);
Integer n2 = new Integer(100);
System.out.println(n1==n2);
System.out.println(n1.equals(n2));
}
}
输出结果:
false
false
虽然我们常常使用equals()方法进行比较值,但是它默认是比较句柄的,很多封装类的比较值得实现,其实都是自己重写的equals()方法。总结一波,equals()方法的默认行为时比较对象的句柄,如果是自定义的类,需要override equals()方法。
关于toString()方法
先上代码,栗子1:
class ToStringClass{
int i;
//public String toString(){
// return "i="+i;
//}
}
public class ToStringTest {
public static void main(String[] args) {
ToStringClass tsc = new ToStringClass();
tsc.i = 100;
System.out.println(tsc.i);
System.out.println(tsc.toString());
System.out.println(tsc);
}
}
输出结果为:
100
ToStringClass@74a14482
ToStringClass@74a14482
栗子2:
class ToStringClass{
int i;
public String toString(){
return "i="+i;
}
}
public class ToStringTest {
public static void main(String[] args) {
ToStringClass tsc = new ToStringClass();
tsc.i = 100;
System.out.println(tsc.i);
System.out.println(tsc.toString());
System.out.println(tsc);
}
}
输出结果为:
100
i=100
i=100
显然栗子2比栗子1只差一个自己重写的toString()方法,,可以得出结论:
(1)或取句柄的字符串属性时候,JVM会自动调用其toString()方法
(2)toString()方法继承于Object,有时候需要重写一波
注:不同类型的实例进行赋值时,只允许将子类的实例赋给父类的句柄。因为面向对象描述的是现实中的事物,有一定逻辑在里面。
类的多态
主要体现:方法的override、upcasting、downward cast
upcasting栗子:
class Upper{
public void f(){
System.out.println("Upper.f()");
}
}
class Down extends Upper{
public void f(){
System.out.println("Down.f()");
}
}
public class Test {
public static void Doit(Upper u){
u.f();
}
public static void main(String[] args) {
Down down = new Down();
Doit(down);
}
}
输出:
Down.f()
downward cast栗子:
public void doSomething(Employee e){
if(e instanceof Manager){
Manager m = (Manager)e;
}
System.out.println("This is the manager 0f"+m.getDepartment)
}
upcasting和downward cast异同点:
相同:
(1)用父类做形参
(2)子类做实参传递
(3)执行子类的方法
不同:
调用父类和子类共同的方法时,upcasting用的是父类就已经有的方法,而downward cast ,用于调用父类无子类有的方法
关于 抽象类、接口、内部类
抽象类:abstract class,不能被实例化为对象。只能被继承使用,抽象类被继承后,必须将所有的抽象方法实现,否则子类依然是抽象类。
抽象方法:(1)abstract关键字(2)只有方法名,没有方法实体
拥有抽象方法的的类一定是抽象类。
内部类:inner class
接口:interface
使用关键字 interface定义,接口中的变量都是final static,接口中没有构造方法,并且定义的成员方法都是抽象方法(默认为abstract),采用多重继承机制。
实现一个接口就具备接口所定义的某个能力或特性
举个栗子: