面向对象
面向对象思想
构造器:new就是一个构造器,作用是:①分配空间;②赋初始值(避免错误,简化输入)
new Object(Parameters)构造器调用构造函数,传参为了赋初始值;
对象的基本元素是:属性和方法 类成员(属性和方法)。属性最为重要,属性的集合是一个状态,方法是一个状态到另一个状态的桥梁
封装:属性和处理属性的方法集合起来。
把数据及数据的操作方法放在一起,作为一个相互依存的整体,即对象。
面向对象是基于面向过程而言的,面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节;这种思想是将数据作为第一位,而方法或者说是算法作为其次,这是对数据一种优化,操作起来更加的方便,简化了过程。
面向对象的三个基本特征
封装,就是把客观的事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的信息隐藏。隐藏实现细节,使得代码模块化。
继承,可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。可以扩展已存在的代码模块。
多态,是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。父类引用指向子类对象。
封装
访问权限的控制常被称为是具体实现的隐藏。把数据和方法包装进类中,以及具体实现的隐藏共同被称为封装。
|
public |
protected |
default |
private |
同类 |
√ |
√ |
√ |
√ |
同包 |
√ |
√ |
√ |
|
子类 |
√ |
√ |
|
|
通用性 |
√ |
|
|
|
public:可以被所有其他类访问
protected:自身、子类、及同一个包中类(接受包外的子类访问)
default:同一包中的类可以访问,声明时没有加修饰符,认为是friendly(拒绝一切外包访问)
private:只能被自己访问和修改
类的访问控制符只有三种:public、private、protected
default是无访问控制符。
继承extend
在一个子类被创建的时候,首先会在内存中创建一个父类对象,然后在父类对象外部放上子类独有的属性,两者合起来形成一个子类的对象。所以所谓的继承使子类拥有父类所有的属性和方法,但是父类对象中的私有属性和方法,子类是无法访问到的,只是拥有,但不能使用。子类不能继承父类的构造函数,只是显式或隐式调用,可以从子类调用超类的构造函数。
用new创建子类的对象时,若子类没有带参构造函数,将先执行父类的无参,然后再执行自己的构造函数。父类定义了有参的构造函数后,可以不定义无参的构造函数,系统也不会提供默认的无参构造函数。这时子类只能调用父类的有参构造函数。
Java类是单继承,Java接口可以多继承。类可以实现多个接口,接口可以继承(扩展)多个接口
先继承后实现接口
组合和继承
组合是指在新类里面创建原有的类的对象,重复利用已有类的功能。(“has - a”)
组合和继承都允许在新的类中设置子对象,只是组合是显式的,而继承是隐式的。组合中的整体类和继承中的子类对应,组合中的局部类和继承中的父类对应。
组合和继承的选择规则:
① 除非两个类之间是“is - a”的关系,否则不要轻易地使用继承。过多的使用继承会破坏代码的可维护性,当父类修改时,会影响所有继承他的子类,增加了程序维护的难度和成本。
②不要仅仅为实现多态而使用继承,如果类之间没有“is - a”关系,可以通过实现接口与组合的方式来达到相同的目的。
多态
http://blog.csdn.net/sinat_18882775/article/details/50154491
定义:不同类的对象对同一消息做出响应。同一消息可以根据发送对象的不同而采用多种不同的行为方式。
多态存在的三个必要条件:继承、重写、父类引用指向子类对象。
Java中多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。
父类引用指向子类对象,该引用不能再访问子类新增的成员。Animal cat = new Cat()
直接new一个父类实例(Animal a = new Animal())的区别?
答:当父类是接口和抽象类时,不能实例化,只能运用多态,向上转型。普通类中,可以在子类中重写父类中的方法,这样就可以访问子类中的重写方法。
重写和重载
方法重载(overload):
(1)必须是同一个类
(2)方法名(也可以叫函数)一样
(3)参数类型不一样或参数数量或顺序不一样
(4)不能通过返回值来判断重载
方法的重写(override)子类重写了父类的同名方法,两同两小一大原则:
(1)方法名相同,参数类型相同
(2)子类返回类型是父类返回类型的子类。
(3)子类抛出异常小于等于父类方法抛出异常,
(4)子类访问权限大于等于父类方法访问权限。
重载(Overload) |
重写(Override) |
同一个类中方法之间的关系,水平关系 |
父类与子类之间,垂直关系 |
通过不同的方法参数来区分(参数的类型,个数,顺序) |
参数列表、返回值类型必须一致,方法体不同 |
不能通过访问权限、返回值类型和抛出的异常类型来进行重载 |
子类访问权限大于等于父类的访问权限 父类中被重写的方法不能为private |
在重写中,运用的是动态单分配,根据new的类型确定对象,从而确定调用的方法
在重载中,运用的是静态多分派,根据静态类型确定对象,不能根据new的类型确定调用方法。
多态中,Father f = new Son()
成员变量:编译运行参考左边;
成员函数:编译看左边,运行看右边;
静态函数:编译运行看左边。
构造函数
用来在对象实例化时初始化对象的成员变量。
特点:
① 方法名必须和类名相同,不能有返回值(也不能为void);
② 一个类可以有多个构造函数,没有定义的话,编译器会在源代码编译成字节码文件的过程中会提供一个没有参数默认的构造方法。若定义后,不会再创建默认的构造方法;
③构造函数的参数有(0到多个);
④构造函数在对象实例化时会被自动调用,且只运行一次;普通方法是在程序执行到时才调用且可以被该对象调用多次;
⑤构造函数的作用是完成对象的初始化;
⑥构造函数不能被继承,不能被覆盖,能被重载。
⑦子类可以通过super()关键字来显示调用父类的构造函数,父类没有提供无参构造,子类的构造函数中必须显式得调用父类的构造函数。
⑧父类和子类都没有定义构造函数时,编译器都会为父类生成一个默认的无参构造,给子类也生成一个默认的无参的构造函数。
⑨构造方法会在成员变量之后初始化。
⑩构造方法不能被static、final、synchronize、abstract、native修饰,但可以被public、private、protect修饰。
在继承的时候,父类当然也有构造方法,如果你要创建子类的对象,那么执行的过程首先是调用父类的无参构造方法生成父类的对象,然后再调用子类的无参构造方法来生成子类对象。继承的时候都是先生成父类的对象,然后再生成子类的对象。
通过使用this关键字带上参数,可以在一个构造函数中调用另外一个构造函数。这是this除了单纯表示"当前对象"(注意是针对对象而不是类的概念)之外的第二个作用。但是注意3点:
第一点,必须放在第一行。
第二点,只能调用一个其它的构造函数。(也许可以这样理解,正是因为有了第一点,如果可以调用多个的话,那么就无法放在"第一行",所以只能允许一次调用)
第三点,只能是构造函数调用构造函数,普通函数无法调用构造函数。
super()和this()
super()关键字表示超类的意思,当前类是从超类继承而来。
this指代当前对象。
只有在重写(Override)父类的方法中,子类要调用继承自父类的方法,才使用super关键字。
使用super()或者this()方法是必须放在构造函数的第一行。
由于this函数指向的构造函数默认有super()方法,所以规定this()和super()不能同时出现在一个构造函数中。
因为static方法或者语句块没有实例时可以使用,而此时不需要构造实例,所以不能用this()和super()。
abstract(抽象类)和Interface(接口)
抽象类
用abstract修饰的类表示抽象类,抽象类位于继承树的抽象层,抽象类不能被实例化。
用abstract修饰的方法表示抽象方法,抽象方法没有方法体。抽象方法用来描述系统具有什么功能,但不提供具体的实现,把具体实现留给继承该类的子类。
特点:
a.含有抽象方法的类必须声明为抽象类(不管其中是否有其他方法)
b.抽象类可以没有抽象方法,可以有普通方法。
c.抽象类必须被继承,抽象方法必须被重写(若子类还是抽象类,不需要重写)
d.抽象类不能被实例化(不能直接构造一个该类的对象)
抽象方法
a.在类中没有方法体(抽象方法只需声明,而不需实现某些功能);
b.抽象类中的抽象方法必须被实现;
c.如果一个子类没有实现父类中的抽象方法,则子类也变成了一个抽象类;
接口
interface 中的方法默认为public abstract (public、abstract可以省略),变量默认为public static final;类中的方法全部都是抽象方法。只有声明没有实现,在不同类中有不同的方法实现。
不同点:
(1)接口中只能包含抽象方法和默认方法,不能为普通方法提供方法实现;抽象类中可以包含普通方法。
(2)接口里不能定义静态方法(jdk1.8下可以定义static方法),抽象类可以定义静态方法。
(3)接口中只能定义静态常量,不能定义普通成员变量;抽象类即可以定义变量又可以定义静态常量。
(4)接口中不包含构造器,抽象类里可以包含构造器,抽象类中的构造器并不是用于创建对象,而是让其他子类调用这些构造器来完成抽象类的初始化操作。
(5)接口里不能包含初始化块,但抽象类可以包含。
(6)一个类最多只能有一个父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足。
共同点:
(1)接口和抽象类都不能被实例化,都位于继承树的顶端,用于被其他类实现的继承。
(2)接口和抽象类都可以包含抽象方法,实现接口和继承抽象类的普通子类都必须实现这些方法。
|
抽象类 |
接口 |
方法 |
普通方法、抽象方法 |
只能有抽象方法和默认方法 |
静态方法 |
可以定义 |
不能定义(jdk1.8下可以定义) |
默认访问权限 |
jdk1.8前为protected jdk1.8后为default |
jdk1.8前为public jdk1.8为public或default |
变量 |
定义变量、静态常量 |
只能定义静态常量 |
构造器 |
可以包含(不是用来创建对象,而是让其他子类调用,完成初始化操作) |
不能包含 |
初始化块 |
可以包含 |
不能包含 |
继承 |
只能有一个父类,但可以实现多个接口 |
接口可以继承多个接口 |
实例化 |
接口和抽象类都不能被实例化,都位于继承树的顶端,用于被其他类实现的继承。 |
final
final修饰的类,就是最终类,不能被继承。
final修饰的方法,就是最终方法,最终方法不能被重写。
final修饰一个引用变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。修饰基本数据类型变量时,内容不能变。
final成员变量必须在初始化代码块或在构造器中初始化。
作用:
final类:如果一个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会再被扩展,那么就设计成final类。
final方法:①把方法锁定,防止任何继承类修改它的意义和实现。②高效,编译器在遇到调用final方法时候会转入内嵌机制,大大提升执行效率。
static
static修饰的变量称为静态变量,静态变量属于整个类,而局部变量属于方法,只在该方法内有效。static不能修饰局部变量。static方法内部不能调用非静态方法。
静态变量只能在类主体中定义,不能在方法中定义。
static变量只会创建一份,不管创建几个对象,都共用一个变量。
类方法指被static修饰的方法,无this指针。其他的就是实例方法。类方法可以调用其他类的static方法
类方法和对象方法的区别
1、类方法是属于整个类的,而实例方法是属于类的某个对象的。
由于类方法是属于整个类的,并不属于类的哪个对象,所以类方法的方法体中不能有与类的对象有关的内容。即类方法体有如下限制:
(1) 类方法中不能引用对象变量;
(2) 类方法中不能调用类的对象方法;
(3) 在类方法中不能使用super、this关键字。(this表示当前类的对象,由static修饰的方法是类直接调用,不需要创建对象,所以不能用this)
(4)类方法不能被覆盖。
2、与类方法相比,对象方法几乎没有什么限制:
(1) 对象方法中可以引用对象变量,也可以引用类变量;
(2) 对象方法中可以调用类方法;
(3) 对象方法中可以使用super、this关键字。
static关键字的作用
为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关;实现某个方法或属性与类而不是对象关联在一起。
静态变量属于类,在内存中只有一个复制,只要静态变量所在的类被加载,这个静态变量就会被分配空间。
类修饰符
http://blog.csdn.net/dawn_after_dark/article/details/74527137
(1)外部修饰类
1、protected 和 private 不能修饰外部类,是因为外部类放在包中,只有两种可能,包可见和包不可见。
2、final 和 abstract不能同时修饰外部类,因为该类要么能被继承要么不能被继承,二者只能选其一。
3、不能用static修饰,因为类加载后才会加载静态成员变量。所以不能用static修饰类和接口,因为类还没加载,无法使用static关键字。
(2)内部修饰类
内部类与成员变量地位一直,所以可以public、protected、default和private,同时还可以用static修饰,表示嵌套内部类,不用实例化外部类,即可调用。
静态块和构造块
public class B{
public static B t1 = new B();
public static B t2 = new B();
{
System.out.println("构造块");
}
static{
System.out.println("静态块");
}
public static void main (String args){
B t = new B();
}
}
以上代码的输出结果是:构造块 构造块 静态块 构造块
(1)静态块:用static声明,JVM加载类时执行,仅执行一次,按声明顺序执行。
(2)构造块:类中直接用{}定义,每一次创建对象时执行
静态域中包含静态变量、静态块和静态方法,其中需要初始化的是静态变量和静态块。而他们两个的初始化顺序是靠他们的位置决定。
静态变量只能在类主体中定义,不能在方法中定义。
执行的顺序优先级:静态域>main()>构造块>构造方法
程序初始化顺序
1.父类静态变量
2.父类静态代码块
3.子类静态变量
4.子类静态代码块
5.父类非静态变量
6.父类非静态代码块
7.父类构造器
8.子类非静态变量
9.子类非静态代码块
10.子类构造器
先静态后非静态,先父类后子类。
按成员变量的定义顺序进行初始化。即使变量定义散布于方法之中。
内部类
为什么使用内部类:
每个内部类都能独立地继承一个接口的实现,所以无论外围类是否已经继承了某个(接口)的实现,对于内部类没有任何影响。能非常好的解决多重继承的问题。
把一个类定义在另一个类的内部,在类里面的这个类就叫做内部类,外面的类叫做外部类。内部类可以被看做外部类的一个成员。内部类分为4种:
静态内部类(static inner class)
被声明为static的内部类,可以不依赖于外部类实例而被实例化,而通常的内部类需要在外部类实例化后才能实例化。静态内部类不能与外部类有相同的名字,不能访问外部类的普通成员变量,只能访问外部类中的静态成员和静态方法。
成员内部类(member inner class)
静态内部类去掉static就是成员内部类,成员内部类为非静态内部类,可以自由地引用外部类的属性和方法,无论静态还是非静态,但是它与实例绑定在一起,不可以定义静态属性和方法。
1.外部类是不能直接使用内部类的成员和方法的,可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法;
2.如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,
可以使用 this 关键字,如:Outer.this.name
局部内部类(local inner class)
局部内部类是定义在一个代码块内的类,它的作用范围为其所在的代码块。局部内部类像局部变量一样,不能别public、protected、private以及static修饰,只能访问方法中的final类型的局部变量。
匿名内部类(anonymous class)
http://www.cnblogs.com/nerxious/archive/2013/01/25/2876489.html
是这一种没有类名的内部类,不使用关键字class、extends、implements,没有构造函数,必须继承其他类或实现一个接口。好处是代码简洁,问题是易读性下降。
匿名内部类不能有构造函数,不能定义静态变量、方法,不能是public、protected、private、static 。只能创建匿名内部类的一个实例,匿名内部类一定是在new的后面。