1、封装性
一个对象和外界的联系应当通过一个统一的接口,应当公开的公开,应当隐藏的隐藏。
属性的封装:Java中类的属性的访问权限的默认值是default,要想隐藏该属性或方法,就可以加private(私有)修饰符,来限制只能够在类的内部进行访问。对于类中的私有属性,要对其给出一对方法(getXxx(),setXxx())访问私有属性,保证对私有属性的操作的安全性。
方法的封装:对于方法的封装,该公开的公开,该隐藏的隐藏。方法公开的是方法的声明(定义),即(只须知道参数和返回值就可以调用该方法),隐藏方法的实现会使实现的改变对架构的影响最小化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public
class
TestDemo {
public
static
void
main(String[] args) {
Person person=
new
Person();
person.tell();
person.setAge(-
20
);
person.setName(
"张三"
);
person.tell();
}
}
class
Person{
private
int
age;
private
String name;
public
int
getAge() {
return
age;
}
public
void
setAge(
int
age) {
if
(age>
0
&&age<
150
){
this
.age = age;
}
}
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
void
tell(){
System.out.println(
"姓名:"
+name+
";年龄:"
+age);
}
}
|
备注:
(1)Java匿名对象:只需要使用一次的场所。例如:new Person().tell();
(2)Java构造方法:构造方法名称必须与类名一致,没有返回指,可以重载,主要为类中的属性初始化。
(3)值传递的数据类型:八种基本数据类型和String(String也是传递的地址,只是String对象和其他对象是不同的,String是final的,所以String对象值是不能被改变的,值改变就会产生新对象。那么StringBuffer就可以了,但只是改变其内容,不能改变外部变量所指向的内存地址)。
引用传递的数据类型:除String以外的所有复合数据类型,包括数组、类和接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public
class
TestRef4 {
public
static
void
main(String args[])
{
int
val=
10
;;
StringBuffer str1, str2;
str1 =
new
StringBuffer(
"apples"
);
str2 =
new
StringBuffer(
"pears"
);
System.out.println(
"val:"
+ val);
System.out.println(
"str1 is "
+ str1);
System.out.println(
"str2 is "
+ str2);
System.out.println(
"..............................."
);
modify(val, str1, str2);
System.out.println(
"val is "
+ val);
System.out.println(
"str1 is "
+ str1);
System.out.println(
"str2 is "
+ str2);
}
public
static
void
modify(
int
a, StringBuffer r1,StringBuffer r2)
{
a =
0
;
r1 =
null
;
r2.append(
" taste good"
);
System.out.println(
"a is "
+ a);
System.out.println(
"r1 is "
+ r1);
System.out.println(
"r2 is "
+ r2);
System.out.println(
"..............................."
);
}
}
|
输出结果为:
1
2
3
4
5
6
7
8
9
10
11
|
val:
10
str1 is apples
str2 is pears
...............................
a is
0
r1 is
null
r2 is pears taste good
...............................
val is
10
str1 is apples
str2 is pears taste good
|
(4)this关键字:表示类中的属性或方法;调用类中的构造方法,例如:this();表示当前对象。
(5)static关键字:static申明属性为全局属性;static申明方法直接通过类名调用;使用static方法时,只能访问static申明的属性和方法,而非static申明的属性和方法时不能访问。
2、继承性
在程序中,使用extends关键字让一个类继承另一个类,继承的类为子类,被继承的类为父类,子类会自动继承父类所有的方法和属性
class 子类 extends 父类{}
示例1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
public
class
ExtendsDemo1 {
public
static
void
main(String[] args) {
Student student=
new
Student();
student.setAge(
15
);
student.setName(
"张三"
);
student.setScore(
90
);
student.tell();
System.out.println(
".............................."
);
System.out.println(
"name:"
+student.getName()+
";age:"
+student.getAge()+
";score:"
+student.getScore());
}
}
class
Person{
private
int
age;
private
String name;
public
int
getAge() {
return
age;
}
public
void
setAge(
int
age) {
this
.age = age;
}
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
}
class
Student
extends
Person{
//private int age;
//private String name;
private
int
score;
//public int getAge() {
//return age;
//}
//public void setAge(int age) {
//this.age = age;
//}
//public String getName() {
//return name;
//}
//public void setName(String name) {
//this.name = name;
//}
public
int
getScore() {
return
score;
}
public
void
setScore(
int
score) {
this
.score = score;
}
public
void
tell(){
System.out.println(
"name:"
+getName()+
";age:"
+getAge()+
";score:"
+getScore());
}
}
|
输出结果:
name:张三;age:15;score:90
..............................
name:张三;age:15;score:90
2.1 在Java中只允许单继承(一个子类只允许有一个父类),子类不能直接访问父类的私有成员
示例2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
public
class
ExtendsDemo2 {
public
static
void
main(String[] args){
PetWorker petWorker=
new
PetWorker();
petWorker.setAge(
20
);
petWorker.setWork(
"teacher"
);
petWorker.tell();
}
}
/**
* 创建类People
* @author Admin
*
*/
class
People{
private
int
age;
public
int
getAge() {
return
age;
}
public
void
setAge(
int
age) {
this
.age = age;
}
}
/**
* 创建Worker类,单继承People类
* @author Admin
*
*/
class
Worker
extends
People{
private
String work;
public
String getWork() {
return
work;
}
public
void
setWork(String work) {
this
.work = work;
}
}
/**
* 创建PetWorker类,单继承Worker类
* @author Admin
*
*/
class
PetWorker
extends
Worker{
public
void
tell() {
System.out.println(
"age:"
+getAge()+
";work:"
+getWork());
}
}
|
输出结果:
age:20;work:teacher
2.2 Java方法重写
定义:方法名称相同,返回值类型相同,参数也相同,其实质就是子类定义了和父类同名的方法。
重写限制:被子类重写的方法不能拥有比父类方法更严格的访问权限,private<default<public。
子类调用父类中的方法:super.方法名(参数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
class
ExtendsDemo1 {
public
static
void
main(String[] args) {
B b=
new
B();
b.tell();
}
}
class
A{
public
void
tell(){
System.out.println(
"父类中的tell方法"
);
}
}
class
B
extends
A{
public
void
tell() {
super
.tell();
System.out.println(
"我重写了tell方法"
);
}
void
say(){
super
.tell();
}
}
|
输出结果:
父类中的tell方法
我重写了tell方法
父类中的tell方法
方法重载与方法重写区别 |
||
方法重载(Overloading) |
方法重写(Override) | |
定义 | 方法名称相同,参数的类型或个数不同 |
方法名称、参数类型、返回值类型全部相同 |
权限要求 | 对权限没有要求 | 被重写的方法不能拥有比父类更加严格的权限 |
范围 | 发生在一个类中 | 发生在继承中 |
2.3 抽象类与接口
final能申明类、方法和属性,使用final申明的类不能被继承,使用final申明的方法不能被重写,使用final申明的变量变成常量(定义时要赋值),常量是不可以修改的。
抽象类:包含一个抽象方法的类就是抽象类。
定义:
abstract class ClassName{
属性
方法
抽象方法
}
(1)抽象方法:申明而未实现的方法,抽象方法必须使用abstract关键字申明,只有方法名和参数,没有方法体。
(2)抽象类被子类继承,子类(若不是抽象类)必须重写抽象类中的所有抽象方法。
(3)抽象类不能实例化,要通过其子类进行实例化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
class
AbstractClassDemo1 {
public
static
void
main(String[] args) {
StuClass stuClass=
new
StuClass();
stuClass.tell();
stuClass.say();
}
}
abstract
class
AbsClass{
int
age;
public
void
tell(){
System.out.println(
"父类中的tell方法"
);
}
public
abstract
void
say();
}
class
StuClass
extends
AbsClass{
@Override
public
void
say() {
System.out.println(
"子类实现父类抽象类中的say抽象方法"
);
}
}
|
接口可以理解为一种特殊的类(没有构造方法),里面全部是由全局常量和公共的抽象方法组成,接口的实现必须通过子类,使用关键字implements,而且子类可以多实现接口。一个接口不能实现(implements)另一个接口,但它可以继承多个其它的接口。接口定义如下:
[修饰符] interface 接口名 [extends 父接口名列表]{
[public] [static] [final] 全局常量;
[public] [abstract] 抽象方法;
}
样例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public
abstract
class
InterfaceDemo1 {
public
static
void
main(
String
[] args) {
InterfaceClass interfaceClass=
new
InterfaceClass();
interfaceClass.print(
1
.0f);
}
}
class
InterfaceClass
implements
CalInterface1,CalInterface2{
@Override
public
void
print(float r) {
System.out.println(
"半径为"
+r+
"的圆面积:"
+getArea(r)+
",周长:"
+getCircumference(r));
}
@Override
public
float getArea(float r) {
float area=PI*r*r;
return
area;
}
@Override
public
float getCircumference(float r) {
float circumference=
2
*PI*r;
return
circumference;
}
}
//定义接口CalInterface1
interface
CalInterface1
{
float PI=
3
.14159f;
//PI默认为public static final类型
float getArea(float r);
//方法getArea()默认为public abstract类型,注意抽象方法没有方法体
public
abstract float getCircumference(float r);
//计算面积
}
//定义接口CalInterface2
interface
CalInterface2
{
void
print(float r);
//打印输出结果
}
//定义接口CalInterface3,继承接口CalInterface1和CalInterface2
interface
CalInterface3
extends
CalInterface1,CalInterface2{
}
|
输出结果:
半径为1.0的圆面积:3.14159,周长:6.28318
抽象类和接口的对比
参数 |
抽象类 | 接口 |
实现 | 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。 | 子类使用关键字implements来实现接口。 |
构造器 | 可以有构造器 | 无构造器 |
修饰符 | 抽象方法可以有public、protected和default这些修饰符 | 接口方法默认修饰符是public。你不可以使用其它修饰符。 |
main方法 | 抽象方法可以有main方法并且我们可以运行它 | 没有main方法 |
多继承 | 抽象类可以继承一个类和实现多个接口 | 接口只可以继承一个或多个其它接口 |
速度 | 要快些 | 慢些 |
(1)如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类。
(2)如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
(3)如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
3、多态性
定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。
多态性的体现:方法的重载和重写;对象的多态性。
多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。
对象的多态性:
向上转型:程序会自动完成
父类 父类对象=子类实例
向下转型:强制类型转换
子类 子类对象=(子类)父类实例
instanceof关键字:用于判断一个引用类型变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例。
示例1:基于继承实现的多态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
public
class
DuoTaiDemo {
public static void main(String[] args) {
function(new Cat());
function(new Dog());
System.out.println(
"................................."
);
/
/
向上转型
Animal a
=
new Cat();
a.eat();
/
/
向下转型
Cat c
=
(Cat) a;
c.catchMouse();
}
public static void function(Animal a) {
a.eat();
/
/
用于子类型有限
/
/
或判断所属类型进而使用其特有方法
if
(a instanceof Cat) {
Cat c
=
(Cat) a;
c.catchMouse();
}
else
if
(a instanceof Dog) {
Dog c
=
(Dog) a;
c.kanJia();
}
}
}
abstract
class
Animal {
abstract void eat();
}
class
Cat extends Animal {
@Override
void eat() {
System.out.println(
"吃鱼"
);
}
void catchMouse() {
System.out.println(
"抓老鼠"
);
}
}
class
Dog extends Animal {
@Override
void eat() {
System.out.println(
"啃骨头"
);
}
void kanJia() {
System.out.println(
"看家"
);
}
}
|
输出结果:
吃鱼
抓老鼠
啃骨头
看家
.................................
吃鱼
抓老鼠
示例2:基于继承实现的多态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
public
class
DuoTaiDemo1 {
public static void main(String[] args) {
A a1
=
new A();
A a2
=
new B();
B b
=
new B();
C c
=
new C();
D d
=
new D();
System.out.println(
"1--"
+
a1.show(b));
System.out.println(
"2--"
+
a1.show(c));
System.out.println(
"3--"
+
a1.show(d));
System.out.println(
"4--"
+
a2.show(b));
System.out.println(
"5--"
+
a2.show(c));
System.out.println(
"6--"
+
a2.show(d));
System.out.println(
"7--"
+
b.show(b));
System.out.println(
"8--"
+
b.show(c));
System.out.println(
"9--"
+
b.show(d));
}
}
class
A {
public String show(D obj) {
return
(
"A and D"
);
}
public String show(A obj) {
return
(
"A and A"
);
}
}
class
B extends A{
public String show(B obj){
return
(
"B and B"
);
}
public String show(A obj){
return
(
"B and A"
);
}
}
class
C extends B{
}
class
D extends B{
}
|
输出结果:
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D
结果分析:
当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法,但是它仍然要根据继承链中方法调用的优先级来确认方法,该优先级由高到低依次为为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
示例3:基于接口实现的多态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
public
class
DuoTaiDemo2 {
public static void main(String[] args) {
work(new USBDisk());
work(new Printer());
}
public static void work(USB u) {
u.start();
System.out.println(
"正在进行中..."
);
u.stop();
}
}
interface USB{
void start();
void stop();
}
class
USBDisk implements USB{
@Override
public void start() {
System.out.println(
"U盘开始工作"
);
}
@Override
public void stop() {
System.out.println(
"U盘停止工作"
);
}
}
class
Printer implements USB{
@Override
public void start() {
System.out.println(
"打印机开始工作"
);
}
@Override
public void stop() {
System.out.println(
"打印机停止工作"
);
}
}
|
输出结果:
U盘开始工作
正在进行中...
U盘停止工作
打印机开始工作
正在进行中...
打印机停止工作
备注:父类对象会调用子类对象重写后的方法。
本文转自stock0991 51CTO博客,原文链接:http://blog.51cto.com/qing0991/1639375,如需转载请自行联系原作者