Java面向对象


面向对象

一,面向对象

 

顾名思义是一个由各种各样的对象组成的世界。它是一种思想,是一种考虑问题的方式。它最终的目的是用一种类似于现实中的对象来模拟出我们要解决的问题的一种思想。

现实中的对象有什么特点呢?概括起来可以说现实中的对象都有自己的特征,而且这些对象都有一些相关的行为。例如:现实中的小狗,它有一些自己的特征如毛色、大小、尾巴的长短等等(可以根据我们所知道的罗列出很多);它还有它的行为,比如见到陌生人它会叫。见到主人它会摇尾巴等等。现实中的所有东西都能总结出类似的东西。面向对象思想就是利用现实中的这些对象的这种特点抽象出了一种特殊的数据结构。这种结构也有自己的特征(属性)和自己的行为(方法)。利用这种思路来模拟现实。达到合理的安排程序的流程的作用。

1、理解面向对象
(1)、面向对象是相对面向过程而言
(2)、面向对象和面向过程都是一种思想
(3)、面向过程
强调是功能行为
(4)、面向对象
将功能封装进对象,强调具备了功能的对象
(5)、面向对象是基于面向过程的
(6)、面向对象三大特征:封装,继承,多态
总结:思想转变从执行者到指挥者的转变!!
正如张老师常说的谁拥有数据谁掌握操作,从原来的面向过程转向把数据放手给对象!!!
2、名词提炼法
人开门:
{
开门(门
){
门.开门
();
}
}
{
开门
(){
操作门轴。

}
}
3
、映射到java中,描述就是class定义的类成员变量可以定义在成员方法后吗?可以
(1)、具体对象就是java在对内存中使用new建立实体。
(2)、类就是现实生活真正事物的描述
(3)、对象就是这类事物,实实在在的个体
(4)、描述事物就是在描述事物的的属性和行为
(5)、属性对应类中的变量,行为对应的类中的函数(方法)
(6)、其实定义类,就是在描述事物,就是在定义属性和行为,属性和行为,共同成为类中的成员(成员变量,成员方法)

4、使用对象
(1)、使用 new 操作符来建立对象
(2)、对象.变量对象.方法()
class Car{
private String color = "red";
private int num = 0;
public void run(){
System.out.pringln("color = "+color+" ; num = "+num);
}
}

class CarDemo{
public static void main(String[] args){
Car c = new Car();
c.color = "blue";
c.run();
}
}
5、成员变量,局部变量

(1)、作用范围:成员变量作用于整个类中,局部变量作用于函数中,或者语句中
(2)、在内存中的位置:成员变量在堆内存中,因为对象的存在,才在内存中存在。局部变量存在于栈内存中
6、匿名对象 多个匿名对象自己管自己 new匿名对象的成员变量无意义,调用成员方法可以!
匿名对象是对象的简化形式,
匿名对象两种使用情况
当对对象方法仅进行一次调用的时候
匿名对象可以作为实际参数进行传递
关于例子的疑问 方法可以直接用吗奇怪。。。。
这个
class Car{
private num;
void run(){
System.out.print("run");
}
public static void show(Car c){
System.out.print("run");
}
public static void main(String[] args){
new Car().run; //
使用匿名对象
show(new Car());
}

}
7
、封装概述
1、封装:是指隐藏对象的属性和实现细节,仅对外提供公共的访问方式
2、好处
(1)、将变化隔离
(2)、便于使用
(3)、提高重用行
(4)、提高安全性
3、封装原则
(1)、将不需要对外提供的内容都隐藏起来
(2)、把属性都隐藏,提供公共方法对其访问
8、private 封装
(1)、private 关键字
是一个权限修饰符
用于修饰成员(成员变量和成员函数)
被私有化的成员只在本类中有效

(2)、常用之一
将成员变变量私有化,对外提供对应的set,get方法对其进行访问,提高对数据访问的安全性
之所以对外提供访问方式,就是因为可以在访问方式中加入逻辑判断等语句
对访问的数据进行操作,提高代码的健壮性

9、对象 用成员变量
对象名.成员变量
10、构造函数

构造函数
特点:1.函数名与类名相同
2.不用定义返回值类型
3.不可以些return语句
作用:给对象进行初始化
注意:1.默认构造函数的特点
2.多个构造函数是以重载的形式存在的

构造函数是在对象一建立就运行。给对象初始化
而一般方法是对象调用才执行,是给对象添加对象具备的功能
一个对象建立,构造函数值运行一次
当分析事物时,该事物存在一些特性或者行为,那么将这些内容定义在构造函数中


class StaticCode {
static {
System.out.println("a");
}
}

public class StaticCodeDemo {
static {
System.out.println("b");
}

public static void main(String[] args) {
new StaticCode();
new StaticCode();
System.out.println("over");
}

static {
System.out.println("c");
}
}

结果:
b
c
a
over

11.优先级:静态代码块、构造代码块、构造函数

细节:
Person p=new Person("zhangsan","20");

关于该句话所做的事情
1.因为new用到了Person.class.所以会先找到Person.class文件并加载到内存
2.执行该类的static代码块,如果有的话,给Person.class类进行初始化
3.在堆内存中开辟空间,分配内存地址
4.在堆内存中建立对象的特有属性,并进行默认初始化
5.对属性进行显示初始化
6.对对象进行构造代码块初始化
7.对对象进行与之对应的构造函数初始化
8.讲内存地址付给栈内存中的p变量

静态:类名.成员
非静态:对象.成员


class Single {
private Single() {
}

private static Single s = new Single();

public static Single getInstance() {
return s;
}
}

// 对象式方法被调用时,才初始化,也叫对象的延时加载 称为:懒汉式
// Single2类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象
class Single2 {
private Single2() {
}

private static Single2 s = new Single2();

public static Single2 geiInstance() {
if (s == null) {
synchronized (Single2.class) {
if (s == null)
s = new Single2();
}
}
return s;
}
}

// 记住原则:定义单例,建议使用饿汉式
public class SingleDemo {
public static void main(String[] args) {

Single ss = Single.getInstance();

}
}

12、this关键字:区分局部变量和成员变量
(1)、this 代表本来的对象,代表它所在函数对象的引用。简单说哪个对象在调用 this 所在的函数,this就代表哪个对象
(2)、是用于区分局部变量和成员变量同名的情况
13、this 关键字 应用!!
class Demo{
privat int age = 0;
Demo(int age){
this.age = age;
}
void compare(Demo d){
return this.age==d.age; //this
为调用该构造函数的对象的引用, }
public static void main(){
Demo d = new Demo(20);
Demo d2 = new Demo(21);
d.compare(d2);
}
}
14、this关键字在构造函数间调用

(1)、this();构造函数,只能放在构造函数的第一行,否则会报错,因为初始化要先执行
class Demo{
privat int age = 0;
privat String name = 0;
Demo(int age){
this.age = age;
}
Demo(String name,int age){
this.name = name; //
这两个是一个,this 就相当于 对象(数据)
this(age); //
this.age = age;
}


public static void main(){
Demo d = new Demo(20);
Demo d2 = new Demo("zhangshuai",21);
}
}

一‘Static关键字
1、static 静态
(1)、是一个修饰符,只能修饰成员(成员变量,成员函数),在内存中的共享区
(2)、 static String s1 = "ddd"; //对象都能访问,共享,但是不在堆内存中
(3)、当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用,方式为: 类名.变量名
2、static 特点
(1)、随着类的加载而加载,当使用类,或者加载到内存中是,这个 static 变量(静态成员变量,类变量)就会 存在,非static变量(成员变量,实例变量),只有对象生成时候,才会加载
也会随着类的消失而消失,声明周期最长
(2)、优先于对象存在
(3)、被所有对象所共享
(4)、可以直接被类名所调用
(5)、因为加载顺序原因,所以可以通过类名来调用static 变量,当有了对象后,才可以使用对象调用非static变量
(6)、因为生命周期长,性能,所以不可以全部定位 静态变量
3、实例变量和类变量的区别
(1)、存放位置
类变量,随着类的加载而存在于方法区中。
实例变量,随着对象的建立而存在于堆内存中(对象里)
(2)、生命周期
类变量声明周期最长,随着类的消失而消失、
实例变量声明周期随着对象的消失而消失
4、静态使用注意事项
(1)、方法也可以使用 static 修饰,但是当方法中,有非静态 变量 时,编译会报错,
因为直接使用 类名访问方法,所以就算使用 this,也不行,因为this 也是对象,但是现在没对象
非静态方法,既可以访问静态,也可以访问非静态
(2)、静态方法中不可以定义this、super关键字
因为静态优先于对象存在,所以静态方法中不可以出现this
(3)、主函数main()是静态的

5、静态有利有弊
(1)、利处:对对像的共享数据进行单独空间的存储,节省空间,没有必要对每一个对象中都存储一份
可以直接被类名调用
(2)、弊端:生命周期过长
访问出现局限性,访问不了非静态。


二、main函数 public


1public static void main(String[] args)
2、主函数:是一个特殊的函数,作为程序的入口,可以被jvm调用

3、主函数定义:
(1)、public:代表着该函数访问权限是最大的。
(2)、static:代表着主函数随着类的加载就已经存在了
(3)、void:主函数没有具体的返回值
(4)、main:不是关键字,但是是一个特殊的单词,可以被jvm识别
(5)、(String[] args):函数的参数,参数类型是一个数组,该数组中的元素是字符串,存储字符串类型元素的数组
4、主函数是固定格式的:jvm识别
5、可以有多个main函数,相当于重载,但是虚拟机只认那个固定格式的。
6、public static void main(String[] args),只有 变量名可以改,args是变量名,可以任意
7、jvm在调用主函数时,会传入 new String[0];args jvm 会传个字符串数组,可以打印出来 [Ljava.lang.String;@6bbc4459
8、可以手动给主函数传值 c:\java>java MainDemo first secoond 以空格分割,也可以直接调用主函数,传入字符串数组

三、静态什么时候使用


1、要从两方面下手,因为静态修饰的内容有成员变量和成员函数。
2、什么时候定义静态变量
(1)、当对象中出现共享数据时,该数据就可以被静态所修饰
(2)、对象中的特有数据要定义成非静态存在于堆内存中
3、什么时候定义静态函数
(1)、当功能内部没有访问到非静态数据(对象的特有数据),那么该功能可以定义成静态的


四、静态的应用-工具类


1、静态的应用
(1)、每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用。 就是接口。

2
、可以考虑让程序更严谨,是不是需要对象,将函数 写为 static 通过类名直接调用
3、将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象
4、为了严谨,应强制让该类不能建立对象,可以通过将构造函数私有化,来完成

五、帮助文档的制作javadoc


1、c:\java>javadoc -d doc -author -version Demo.javadoc 为目录,、
2、该类必须写成 public 否则会报错
c:\java>javadoc -d doc -author -version Demo.java
正在装入源文件 Demo.java...
正在构造 Javadoc 信息
...
javadoc: 错误 - 找不到可以文档化的公共或受保护的类

1 错误
3、只有设为 public 和 protect 的函数 才会提取
4、如果不写权限,则也不会提取
5、一个类中会有一个默认的空构造函数,这个构造函数的权限和本类一致,如果该类被修饰为public,反之,该类没有被public修饰,则该构造函数也不为public


六、静态代码块


1、格式
static{
静态代码块中的执行语句;
}
2
、特点
(1)、随着类的加载而执行,只执行一次,跟普通的 代码块 不同,普通的代码块是
(2)、给类进行初始化
(3)、先于主函数执行
不能范围非静态成员


七、对象的初始化过程

Person p=newPerson("sds",22);
1、因为 使用对象 new 用放到了 该类,所以会先找到 该类文件 并加载到内存中

2、执行该类中的 static 代码块,如果有的话,给 该类 进行初始化
3、在堆内存中开辟空间,分配内存地址
4、在堆内存中建立对象的特有属性,并进行默认初始化
5、对属性进行显示初始化
6、对对象进行构造代码快初始化
7、对对象进行对应的构造函数初始化
8、将内存地址赋给栈内存中的 对象 变量


八、对象调用成员过程


1、类成员和类变量载入对内存中
2、方法和静态变量载入到方法区中
3、栈中的方法和变量只是对堆内存的引用


九、设计模式:

 

解决某一类问题最行之有效的方法,java中存在23种设计模式。
1、单例设计模式:解决一个类在内存中只存在一个对象
(1)、要想保证对象唯一
(2)、为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象
(3)、还可以为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象。
(4)、为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
2、实现
(1)、将构造函数私有化,
(2)、在类中创建一个本类对象
(3)、提供一个方法可以获取到该对象
3、注意
(1)、对于事物该怎么描述,还怎么描述
(2)、当需要将该事物的对象保证在内存中唯一时,就将以上的三步加上即可
' private static Student s = new Student();
05. public static Student getInstance(){
06. return s;
07. }

public static Student getInstance(){ //synchronized

if(s==null)

s = new Student();
10.
11. return s;
12. }

6、两种区别
(1)、第一种是先初始化对象,成为 饿汉式
(2)、第二种是对象是被调用时,才初始化,也叫做对象的延时加载,称为,懒汉式。
(3)、第一种是 类 一进入 内存,就已经创建好了对象
(4)、第二种是 类 进入 内存,对象 还未创建 ,只有调用了 创建对象的方法时,才建立对象
(5)、开发一般用 第一种,因为安全简单
(6)、所以第二种 应该加上 关键字,相当于锁 synchronized,但是效率会很低,
(7)、第二种解决方案,最终方案,是把synchronized 放入,判断内,判断两次
(8)、但是第二种依然会很慢,所以建议使用饿汉式

封装、继承、多态

面向对象还有几个重要的特征是必须记住的,那就是:封装、继承、多态。其实这三个重要的特性也是从现实世界中抽象出来的。

(一)、封装

封装就是将一些保密的东西密封起来,让外界不可见。现实中到处可以看到这种事情。

a. 封装就是将属性私有化,提供公有的方法访问私有属性。具体做法就是:修改属性的可见性来限制对属性的访问,并为每个属性创建一对取值(get)方法和赋值方法(set),用于对这些私有属性的访问。

b.this关键字

this是在对象内部指代自身的引用,this可以直接引用自身对象,但凡本类功能内部使用了了本类对象,都用this表示,解决了实例变量和局部变量之间重名而引发的冲突;this语句(this();)用于构造函数之间进行互相调用,只能定义在构造函数的第一行,因为初始化要先执行。

c.private关键字

权限修饰符:用于修饰类中的成员(成员变量,成员函数)。私有只在本类中有效。私有仅仅是封装的一种表现形式。变量一旦被私有化,其他类都不能直接访问这些属性,只能通过这些属性的取值、赋值方法来访问。

d.封装的好处

1.实现了对属性数据的数据访问权限的限制;

2.避免了大规模的修改,增强了程序的可维护性。

e.构造方法

构造方法负责对象成员的初始化工作,为实例变量赋予合适的初始值,使用new关键字实例化一个对象其实就是调用这个对象的构造方法。

构造方法中方法名必须与类名相同,并且没有返回值类型!

在使用带参数的构造方法实例化对象时,传递的值和构造方法的参数必须要在个数、次序和数据类型上相匹配。

f.方法重载

如果两个方法名相同,但参数项不同,那么一个方法就是另一个方法的重载形式。构造方法的重载就是一个典型的特例,一般我们可以通过重载构造方法完成对象的多种实例化行为。

(二)继承

继承可能是我们在面向对象思想中最容易接受的一种特点,因为我们在现实中经常听到这个词,而且在面向对象思想中的继承也类似于现实中的继承。但是继承又是我们在应用面向对象解决问题的时候最难用的一种特性。

1.继承的特点

父类更通用、子类更具体。也就是说父类具有更一般的特征和行为,而子类中除了具有父类的特征和行为外,还具有自己独特的行为和特征。

2.在继承关系中,父类和子类需要满足is-a的关系,比如,兔子 is a 食草动物,这样两者才能满足继承关系。在java中用extends关键字来表示一个类继承了另一个类,如:A entends B 。java不支持多继承,但可以实现多接口。

3.方法重写(覆盖)

如果子类中定义的一个方法,其名称、返回值类型以及参数列表正好与父类中某个方法中的名称、返回值、参数列表相匹配,那么可以说子类的方法重写了父类的方法。

当子类继承父类,沿袭了父类的功能到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致,这时,没有必要定义新功能,而是使用覆盖方法,保留父类的功能定义,并重写功能内容。

子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败,并且静态只能覆盖静态。

4.子类的实例化过程

子类可以直接获取父类中的数据,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。因此子类在对象初始化时,要先访问一下父类中的构造函数。如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。子类的所有的构造函数,默认都会访问父类中空参数的构造函数,因为子类每一个构造函数内的第一行都有一句隐式super();当父类中没有空参数的构造函数时,类必须手动通过super语句形式来指定要访问父类中的构造函数。子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。

super语句一定定义在子类构造函数的第一行。

5.抽象类

a.被abstract修饰的类就是一个抽象类,抽象类一定是一个父类,给子类提供实例的初始化。

b.抽象方法和抽象类都必须被abstract关键字修饰,并且抽象方法一定在抽象类中。

c.抽象类不可以用new创建对象,因为调用抽象方法没意义。

d.抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用。如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。

e.abstract 关键字和一下关键字不能共存:

final:被final修饰的类不能有子类,而被abstract修饰的类一定是一个父类。

private: 抽象类中的私有的抽象方法,不被子类所知,就无法被复写,而抽象方法出现的就是需要被复写。

static:如果static可以修饰抽象方法,那么连对象都不用建立了,直接类名调用就可以了,但是抽象方法没有方法主体,所以运行没意义。

6.继承的好处:

提高了代码的复用性,让类与类之间产生了关系,有了这个关系,才有了多态的特性。

(三)多态

多态也是一种现实中存在而且经常用到的特性,不过我们平常不怎么注意罢了。例如,早上你和朋友见面,朋友问你吃饭了没有。其实这个问题就是一种多态。

1.多态是具有表现多种形态的能力特征,也可以说,同一个实现接口,使用不同的实例而执行不同的操作。

2.多态的体现
父类的引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象。
3.多态的前提
必须是类与类之间有关系,要么继承,要么实现。通常还有一个前提:存在覆盖。

4.多态的好处
多态的出现大大的提高程序的扩展性,但是只能使用父类的引用访问父类中的成员。

5.多态的实现步骤:

a.子类重写父类的方法;

b.把父类类型作为参数类型,该父类及其子类对象作为参数传入;

c.运行时根据实际创建的对象类型动态决定使用哪个方法。

class Father{

    public voidfunc1(){

        func2();

    }

    //这是父类中的func2()方法,因为下面的子类中重写了该方法

    //所以在父类类型的引用中调用时,这个方法将不再有效

    //取而代之的是将调用子类中重写的func2()方法

    public voidfunc2(){

       System.out.println("AAA");

    }

}

 

class Child extends Father{

    //func1(int i)是对func1()方法的一个重载

    //由于在父类中没有定义这个方法,所以它不能被父类类型的引用调用

    //所以在下面的main方法中child.func1(68)是不对的

    public voidfunc1(int i){

        System.out.println("BBB");

    }

    //func2()重写了父类Father中的func2()方法

    //如果父类类型的引用中调用了func2()方法,那么必然是子类中重写的这个方法

    public voidfunc2(){

       System.out.println("CCC");

    }

}

 

public class PolymorphismTest {

    public staticvoid main(String[] args) {

        Father child= new Child();

       child.func1();//打印结果将会是什么?   

    }

}

    上面的程序是个很典型的多态的例子。子类Child继承了父类Father,并重载了父类的func1()方法,重写了父类的func2()方法。重载后的func1(int i)和func1()不再是同一个方法,由于父类中没有func1(int i),那么,父类类型的引用child就不能调用func1(int i)方法。而子类重写了func2()方法,那么父类类型的引用child在调用该方法时将会调用子类中重写的func2()。

 

    那么该程序将会打印出什么样的结果呢?

 

    很显然,应该是“CCC”。

    对于多态,可以总结它为:

    一、使用父类类型的引用指向子类的对象;

    二、该引用只能调用父类中定义的方法和变量;

    三、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)

    四、变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。

 


 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值