@Mahdi
2018-02-26T20:39:59.000000Z
字数 8275
阅读 899
java
类型,引用,对象,行为,多态,封装,继承
特点
- 面向对象就是一种常见的思想,符合人们的思考习惯
- 将复杂问题简单化
- 让曾经在面向过程中的执行者,变成了面向对象中的指挥者
面向过程强调的时过程(动作)
面向对象强调的时对象(实体)
java语言对现实生活中的事物进行描述,是通过类的形式来体现。
怎么描述呢?
对于事物描述通常只关注两方面。
一个是属性,一个是行为。
只要明确该事物的属性和行为并定义在类中即可。
对象:其实就是该类事物实实在在存在的个体
类与对象之间的关系?
类:事物的描述。
对象:该类事物的实例。在java中通过new来创建的。
注:对象内存图解
1.
成员变量定义在类中,整个类中都可以访问。
局部变量定义在方法(函数),语句,局部代码块中,
只在所属的区域有效,不属于某个对象,
执行结束,变量就不再起作用了。
2.
成员变量存在于堆内存的对象中。
局部变量存在于栈内存的方法中。
3.
成员变量随着对象的创建而存在,随着对象的消失而消失。
局部变量随着所属区域的执行而存在,随着所属区域的结束而释放。
4.
成员变量都有默认初始化值。
局部变量没有默认初始化值。
基本数据类型与引用数据类型参数传递
//基本数据类型参数传递
class Demo
{
public static void main(String[] args)
{
int x = 3;
show(x);
System.out.println("x="+x);
}
public static void show(int x)
{
x = 4;
}
}
//引用数据类型参数传递
class Demo
{
int x = 3;
public static void main(String[] args)
{
Demo d = new Demo();
d.x = 9;
show(d);
System.out.println(d.x);
}
public static void show(Demo d)
{
d.x = 4;
}
}
private:私有,是一个权限修饰符。用于修饰成员。私有的内容只在本类中有效。
注意:私有仅仅是封装的一种体现而已。
构造创建对象时调用的函数。作用:可以给对象进行初始化。
特点
1.函数名与类名相同
2.不用定义返回值类型
3.没有具体的返回值
创建对象都必须要通过构造函数初始化。
一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数。
如果在类中定义了指定的构造函数,那么类中的默认构造函数就没有了。
构造函数可以调用一般函数,一般函数不能调用构造函数
细节
1.构造函数如果完成了set功能。set方法是否需要。
2.一般函数不能直接调用构造函数。
3.构造函数如果前面加了void就变成了一般函数。
4.构造函数中是有return语句的。
构造函数之间的调用以及this关键字
当成员变量和局部变量重名,可以用关键字this来区分。
this : 代表对象。代表哪个对象呢?当前对象。
this就是所在函数所属对象的引用。
简单说:哪个对象调用了this所在的函数,this就代表哪个对象。
this也可以用于在构造函数中调用其他构造函数。
注意:只能定义在构造函数的第一行。因为初始化动作要先执行。
static的特点:
1.static是一个修饰符,用于修饰成员。
2.static修饰的成员被所有的对象所共享。
3.static优先于对象存在,因为static的成员随着类的加载就已经存在了。
4.static修饰的成员多了一种调用方式,就可以直接被类名所调用。类名.静态成员 。
5.static修饰的数据是共享数据,对象中的存储的是特有数据。
可不可以都定义成static??
1.两个变量的生命周期不同。
成员变量随着对象的创建而存在,随着对象的被回收而释放。
静态变量随着类的加载而存在,随着类的消失而消失。
2.调用方式不同。
成员变量只能被对象调用。
静态变量可以被对象调用,还可以被类名调用。
3.别名不同。
成员变量也称为实例变量。
静态变量称为类变量。
4.数据存储位置不同。
成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据.
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据.
静态使用的注意事项:
1,静态方法只能访问静态成员。(非静态既可以访问静态,又可以访问非静态)
2,静态方法中不可以使用this或者super关键字。
3,主函数是静态的。
注:内存图画画
静态什么时候用?
1.静态变量。
当分析对象中所具备的成员变量的值都是相同的 。
这时这个成员就可以被静态修饰。
只要数据在对象中都是不同的,就是对象的特有数据,必须存储在对象中,是非静态的。
如果是相同的数据,对象不需要做修改,只需要使用即可,不需要存储在对象中,定义成静态的。
2.静态函数。
函数是否用静态修饰,就参考一点,就是该函数功能是否有访问到对象中的特有数据。
简单点说,从源代码看,该功能是否需要访问非静态的成员变量,如果需要,该功能就是非静态的。
如果不需要,就可以将该功能定义成静态的。当然,也可以定义成非静态,
但是非静态需要被对象调用,而仅创建对象调用非静态的
没有访问特有数据的方法,该对象的创建是没有意义。
随着类的加载而执行,而且只执行一次
用于给类进行初始化
给所有对象进行初始化
构造函数是给对应的对象进行针对性的初始化
限定局部变量的生命周期
通过关键字extends让类与类之间产生继承关系。
class SubDemo extends Demo{}
继承的出现提高代码的复用性
让类与类之间产生了关系,给第三个特征多态提供了前提
java只支持单继承:一个子类只能有一个直接父类。
class SubDemo extends Demo{}//ok
class SubDemo extends Demo1,Demo2...{}//error
但java可以支持多实现:一个类可以实现多个接口
class SubDemo implements DemoListener1,DemoListener2...{}//ok
java同样支持多层继承,C继承B,B继承A,就会出现继承体系。
class A{}
class B extends A{}
class C extends B{}
什么时候定义继承呢?
当类与类之间存在所属关系的时候,就定义继承。xxx是yyy中的一种,xxx extends yyy
所属关系:is a 关系
注意:不要仅为了获取其他类中某个功能而去继承
1.成员变量
当本类的成员变量与局部变量同名用this区分
当子父类中的成员变量重名用super区分
this代表一个本类对象的引用
super代表一个父类空间
2.成员函数
当子父类中出现成员函数一模一样的情况下,会运行子类的函数
这种现象,成为覆盖(重写)操作(私有方法不可以被重写)。这是函数在子父类中的特性
函数两个特性:
1).重载,同一个类中
2).重写,子类中
重写注意事项:
1).子类方法重写父类方法时,子类权限必须大于等于父类权限(父类private不行)
2).静态只能覆盖静态,或被静态覆盖
什么时候使用重写?
当对一个类进行子类的扩展时,子类需要保留父类的功能声明
但是要定义子类中该功能的特有内容时,就是用重写。(手机升级)
在子类构造对象时,发现,访问子类构造函数时,父类也运行了。
为什么呢?
原因是:在子类的构造函数中第一行有一个默认的隐式语句。 super();
子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数。
为什么子类实例化的时候要访问父类中的构造函数呢?
那是因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前,要先看父类是如何对自己的内容进行初始化的。
所以子类在构造对象时,必须访问父类中的构造函数。
为了完成这个必须的动作,就在子类的构造函数中加入了super()语句。
如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确要调用父类中哪个构造函数。
同时子类构造函数中如果使用this调用了本类构造函数时,
那么super就没有了,因为super和this都只能定义第一行。所以只能有一个。
但是可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。
注意:supre语句必须要定义在子类构造函数的第一行。因为父类的初始化动作要先完成。
一个对象实例化过程:
Person p = new Person();
继承的弊端,打破了封装性
final关键字:
1.final是一个修饰符,可以修饰类,方法,变量。
2.final修饰的类不可以被继承。
3.final修饰的方法不可以被覆盖。
4.final修饰的变量是一个常量,只能赋值一次。
为什么要用final修饰变量。其实在程序如果一个数据是固定的,
那么直接使用这个数据就可以了,但是这样阅读性差,所以它该数据起个名称。
而且这个变量名称的值不能变化,所以加上final固定。
写法规范:常量所有字母都大写,多个单词,中间用_连接。
抽象:笼统,模糊,不具体。就是从多个事物中将共性的,本质的内容抽取出来。
抽象类:Java中定义没有方法体的方法,该方法的具体实现由子类完成,该方法就称为抽象方法,包含抽象方法的类就是抽象类。
抽象方法的由来:多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
abstract class Demo{
abstract void show();
}
class DemoA extends Demo{
void show(){
Sop("showA"):
}
}
class DemoB extends Demo{
void show(){
Sop("showB"):
}
}
特点:
细节:
1.抽象类中有构造函数吗?
有,用于给子类对象初始化
2.抽象类可以不定义抽象方法吗?
可以的,但是很少见,目的就是不让该类创建对象。
AWT的适配器对象就是这种累,通常这种类中的方法有方法体,但却没有内容。
abstract class Demo
{
void show1(){}
void show2(){}
}
3.抽象关键字不可以和哪些关键字共存?
private 不行。抽象方法需要被覆盖
static 不行。还需要对象吗?
final 不行。不准覆盖?
4.抽象类和一般类的区别?
相同点:
都是描述事物的,都在内部定义可成员
不同点:
1.一般类有足够的信息描述
抽象类描述事物的信息不足
2.一般类中不能定义抽象方法,只能定义非抽象方法。
抽象类中可定义抽象方法,同时也可以定义非抽象方法
3.一般类可以被实例化
抽象类不可以被实例化
5.抽象类一定是个父类吗?
是的。因为需要子类覆盖其方法后才可以对子类实例化
当一个抽象类中的方法都是抽象方法的时候,这时可以将该抽象类用另一种定义和表示,就是接口interface
对于接口当中常见的成员,而且这些成员都有固定的修饰符(就算不写,自动加):
由此得出结论,接口中的成员都是公共权限。
interface Demo{//编译完还是class文件
public static final int NUM=4;//int NUM=4;
public abstract void show1();//void show1();
public abstract void show2();//void show2();
}
类与类之间是继承关系,类与接口之间是实现关系
接口不可以实例化,只能由实现了接口的子类并覆盖了接口中所有的抽象方法后,该子类才可以实例化。否则这个子类就是一个抽象类
class DemoImpl implements Demo{}
DemoImple d=new DemoImpl();
d.NUM;//ok
d.NUM=4;//error
DemoImpl.NUM;//ok
Demo.NUM;//ok
接口的特点:
共性:都是不断抽取出来的抽象概念
区别1:抽象体现继承关系,一个类只能单继承
接口体现实现关系,一个类可以多实现
区别2:抽象类是继承,是 is a 关系
接口是实现,是 like a 关系
区别3:抽象类中可以定义非抽象方法,供子类直接使用
接口的方法都是抽象,接口中的成员都有固定修饰符
举例,犬与导盲犬
某一类事物的多种存在形态
class 动物{}
class 猫{}
class 狗{}
猫 x=new 猫();
动物 x=new 猫();//一个对象,两种形态
猫这类事物既具备了猫的形态,又具备着动物的形态。这就是对象的多态。
简单说:就是一个对象对应着不同类型
在代码中的体现:父类或者接口的引用指向其子类对象
abstract class Animal{
absrtact eat();
}
class Dog extends Animal{
void eat(){
sop("啃骨头");
}
void lookHome(){
sop("看家");
}
}
class Cat extends Animal{
void eat(){
sop("吃鱼");
}
void catchMouse(){
sop("抓老鼠");
}
}
Cat c=new Cat();
Dog d=new Dog();
method(c);
method(d);
public static void method(Animal a){
a.eat();
}
多态的好处:提高了代码的扩展性,前期定义的代码可以使用后期的内容
多态的弊端:前期定义的内容不能使用(调用)后期子类的特有内容
多态的前提:1.必须有关系,继承,实现;2.要有覆盖
Animal a=new Cat();
在这里,进行了自动类型提升,专业讲就是向上转型,但是限制了子类特有功能的访问
如果非要访问子类特有功能,向下转型
Cat c=(Cat)a;
但是不能这样子转型
Animal a=new Animal();
Cat c=(Cat)a;
也不能这样
Animal a=new Dog();
Cat c=(Cat)a;//ClassCastException
注意转型,自始至终都是子类对象在做着类型的变化!!
判断类型,instanceof
成员变量在多态的特点
只看引用变量所属的类
class Fu{int num=3;}
class Zi{int num=4};
Fu f=new Zi();
f.num->3
成员函数在多态的特点:
简单说,编译看左边,运行看右边
静态函数在多态的特点:
只依赖其引用变量所属的类
访问特点:
class Outer{//铁扇公主
class Inner{//孙悟空
}
}
有什么用?
一般用于类的设计。
分析事物时,发现该类事物描述中还有事物,而且这个事物还在访问被描述事物的内容。这时就是还有的事物定义成内部类来描述。
class Outer{
private int num=3;
class Inner{
void show(){
System.out.println("show run..."+num);
}
}
public void method(){
Inner in=new Inner();
in.show();
}
}
内部类是对象特有数据时(成员类),访问外部类中内部类的成员:
Outer.Inner in=new Outter().new Inner();
内部类是对象共享数据时(静态类),访问外部类中内部类的成员:
Outer.Inner in=new Outter.Inner();
内部类是对象共享数据时(静态类),访问外部类中内部类的静态成员:
Outer.Inner.成员
注意:当内部类定义了静态成员,该内部类也必须定义静态
class Outer{
int num=3;
class Inner{
int num=4;
void show(){
int num=5;
System.out.println(num);
}
}
void method(){
new Inner().show();
}
}
Object类是类层次结构的根类。每个类都是用Object作为父类。所有对象都实现这个类的方法。
指示其他某个对象是否与此对象“相等”。 其实比的就是引用!看源码
当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
返回该对象的哈希码值。调用c语言实现,看源码!
由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
返回该对象的字符串表示。通常,toString 方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明但易于读懂的信息表达式。建议所有子类都重写此方法。
Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于:
getClass().getName() + '@' + Integer.toHexString(hashCode())
它不是语法规范,是习惯性编程规范,用这个规范写的类使用方便。
1)必须有包
2)具有无参构造函数
3)setter和getter方法
4)必须实现序列化接口
public protected default private
同一类中 ok ok ok ok
同一包中 ok ok ok
子类当中 ok ok
不同包中 ok