面向对象思想引入
前面我们讲过数组,当有多个数组都需要遍历时,我们可以将遍历的代码封装到方法中,需要遍历时,就调用相应的方法即可,提高代码的复用性。在对数组遍历的基础上继续增加需求,比如获取最值,数值逆序等,同样需要将这些功能封装到相应的方法中。这样继续封装会发现方法越来越多,于是就想能不能将这些方法继续进行封装呢?通过前面的讲解我们知道类是可以存放方法的,所以,我们就考虑使用类封装来这多个方法,将来再做数组的操作时,不用去找具体的方法,先找到这个类,然后使用这个类中的方法。这就是面向对象思想的编程方式。
面向过程思想概述
我们来回想一下,这几天我们完成一个需求的步骤:首先是搞清楚我们要做什么,然后在分析怎么做,最后我们再代码体现。一步一步去实现,而具体的每一步都需要我们去实现和操作。这些步骤相互调用和协作,完成我们的需求。
在上面的每一个具体步骤中我们都是参与者,并且需要面对具体的每一个步骤和过程,这就是面向过程最直接的体现。
那么什么是面向过程开发呢? 面向过程开发,其实就是面向着具体的每一个步骤和过程,把每一个步骤和过程完成,然后由这些功能方法相互调用,完成需求。
面向过程的代表语言:C语言
面向对象思想概述
当需求单一,或者简单时,我们一步一步去操作没问题,并且效率也挺高。可随着需求的更改,功能的增多,发现需要面对每一个步骤很麻烦了,这时就开始思索,能不能把这些步骤和功能在进行封装,封装时根据不同的功能,进行不同的封装,功能类似的封装在一起。这样结构就清晰了很多。用的时候,找到对应的类就可以了。这就是面向对象的思想。接下来我们看看面向对象到底是什么?
面向对象思想特点
是一种更符合我们思想习惯的思想
可以将复杂的事情简单化
将我们从执行者变成了指挥者
角色发生了转换
面向对象特征
封装(encapsulation)
继承(inheritance)
多态(polymorphism)
类与对象关系
类:是一组相关的属性和行为的集合
对象:是该类事物的具体体现
举例:
类 学生
对象 班长就是一个对象
成员变量和局部变量的区别
在类中的位置不同
成员变量 类中方法外
局部变量 方法内或者方法声明上
在内存中的位置不同
成员变量 堆内存
局部变量 栈内存
生命周期不同
成员变量 随着对象的存在而存在,随着对象的消失而消失
局部变量 随着方法的调用而存在,随着方法的调用完毕而消失
初始化值不同
成员变量 有默认的初始化值
局部变量 没有默认的初始化值,必须先定义,赋值,才能使用。
匿名对象
匿名对象:就是没有名字的对象。
是对象的一种简化表示形式
匿名对象的两种使用情况
对象调用方法仅仅一次的时候
作为实际参数传递
void show( Person p ){}
Person p = new Person();
show( p );
show( new Person() )
封装概述
是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:
隐藏实现细节,提供公共的访问方式
提高了代码的复用性
提高安全性。
封装原则:
将不需要对外提供的内容都隐藏起来。
把属性隐藏,提供公共方法对其访问。
private关键字:
是一个权限修饰符。
可以修饰成员(成员变量和成员方法)
被private修饰的成员只在本类中才能访问。
private最常见的应用:
把成员变量用private修饰
提供对应的getXxx()/setXxx()方法
class Student {
private String name;
private int age;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
}
class Test1 {
public static void main(String[] args) {
Student s=new Student();
s.setName("张三");
System.out.println(s.getName());
s.setAge(20);
System.out.println(s.getAge());
}
}
this关键字
this:代表所在类的对象引用
记住:
方法被哪个对象调用,this就代表那个对象
什么时候使用this呢?
局部变量隐藏成员变量
构造方法作用概述
给对象的数据进行初始化
构造方法格式
方法名与类名相同
没有返回值类型,连void都没有
没有具体的返回值
构造方法注意事项
如果你不提供构造方法,系统会给出默认构造方法
如果你提供了构造方法,系统将不再提供
构造方法也是可以重载的
类的成员方法
方法具体划分:
根据返回值
有明确返回值方法
返回void类型的方法
根据形式参数
无参方法
带参方法
一个基本类的标准代码写法
类
成员变量private
构造方法
无参构造方法
带参构造方法
成员方法
getXxx()
setXxx()
给成员变量赋值的方式
无参构造方法+setXxx()
带参构造方法
类的初始化过程
Student s = new Student();在内存中做了哪些事情? private String name="张三";
加载Student.class文件进内存
在栈内存为s开辟空间
在堆内存为学生对象开辟空间
对学生对象的成员变量进行默认初始化
对学生对象的成员变量进行显示初始化
通过构造方法对学生对象的成员变量赋值
学生对象初始化完毕,把对象地址赋值给s变量
static关键字
可以修饰成员变量和成员方法
static关键字特点
随着类的加载而加载
优先于对象存在
被类的所有对象共享
这也是我们判断是否使用静态关键字的条件
可以通过类名调用
static关键字注意事项
在静态方法中是没有this关键字的
静态方法只能访问静态的成员变量和静态的成员方法
代码块
在Java中,使用{}括起来的代码被称为代码块,根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块(多线程讲解)。
局部代码块
在方法中出现;限定变量生命周期,及早释放,提高内存利用率
构造代码块
在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
静态代码块 在类中方法外出现,加了static修饰
在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且值执行一次。
class Demo {
//静态代码块
static {
System.out.println("我是静态代码块");
}
//构造代码块
{
int j = 5;
System.out.println("j="+j);
}
public Demo(){
System.out.println("空参数构造方法");
}
//构造代码块
{
int k = 25;
System.out.println("k="+k);
}
}
class CodeBlockDemo {
public static void main(String[] args) {
//局部代码块
{
int i = 5;
//System.out.println("i=" + i);
}
//System.out.println("i --- "+i);
//---------------------------
new Demo();
System.out.println("----------------");
new Demo();
System.out.println("----------------");
new Demo();
}
}
静态代码块与 构造代码块 与 构造方法 的执行顺序?
静态代码块 -->构造代码块 --> 构造方法
class Demo {
//静态代码块
static {
System.out.println("aaa");
}
//构造代码块
{
System.out.println("bbb");
}
//构造方法
public Demo(){
System.out.println("ccc");
}
//构造代码块
{
System.out.println("ddd");
}
//静态代码块
static {
System.out.println("eee");
}
}
class CodeBlockTest {
//静态代码块
static {
System.out.println("000");
}
public static void main(String[] args) {
new Demo();
System.out.println("---------");
new Demo();
System.out.println("---------");
new Demo();
System.out.println("---------");
}
}
结果为000
aaa
eee
bbb
ddd
ccc
继承概述
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
通过extends关键字可以实现类与类的继承
class 子类名 extends 父类名 {} Object
单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。
有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。
如:
class Student {
private String name;
private int age;
public Student(){}
public Student(String name, int age){
this.name = name;
this.age = age;
}
//setXxx() getXxx()
}
class Teacher {
private String name;
private int age;
public Teacher(){}
public Teacher(String name, int age){
this.name = name;
this.age = age;
}
//setXxx() getXxx()
}
发现上面书写的代码,代码重复量太多,可以把相同的代码 抽取出来,放到单独的一个类中,然后让其他的类 与 这个单独类的产生关系
使用继承:
class Person {
private String name;
private int age;
public Person(){}
public Person(String name, int age){
this.name = name;
this.age = age;
}
//setXxx() getXxx()
}
class Student extends Person {}
class Teacher extends Person {}
class ExtendsDemo {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
继承的好处
提高了代码的复用性
多个类相同的成员可以放到同一个类中
提高了代码的维护性
如果功能的代码需要修改,修改一处即可
让类与类之间产生了关系,是多态的前提
其实这也是继承的一个弊端:类的耦合性很强
Java中继承的注意事项
子类只能继承父类所有非私有的成员(成员方法和成员变量)
其实这也体现了继承的另一个弊端:打破了封装性
子类不能继承父类的构造方法,但是可以通过super(后面讲)关键字去访问父类构造方法。
不要为了部分功能而去继承
什么时候使用继承?
继承中类之间体现的是:”is a”的关系。
Java中的继承特点
1:继承关系是传递的。若类C继承类B,类B继承类A(多继承),则类C既有从类B那里继承下来的属性与方法,也有从类A那里继承下来的属性与方法,还可以有自己新定义的属性与方法。继承来的属性和方法尽管是隐式的,但仍是类C的属性和方法。继承是在一些比较一般的类的基础上构造、建立和扩充新类的最有效的手段。
2:继承简化了人们对事物的认识和描述,能清晰体现相关类间的层次结构关系。
3:继承提供了软件复用功能。若类B继承类A,那么建立类B时只需要再描述与基类(类A)不同的少量特征(数据成员和成员方法)即可。这种做法能减小代码和数据的冗余度,大大增加程序的重用性。
4:继承通过增强一致性来减少模块间的接口和界面,大大增加了程序的易维护性。
5:提供多重继承机制。从理论上说,一个类可以使多个一般类的特殊类,它可以从多个一般类中继承属性与方法,这便是多重继承。Java出于安全性和可靠性的考虑,仅支持单重继承,而通过使用接口机制来实现多重继承。
java中继承的注意事项
子类只能继承父类所有非私有的成员(成员方法和成员变量)
其实这也体现了继承的另一个弊端:打破了封装性
子类不能继承父类的构造方法,但是可以通过super(后面讲)关键字去访问父类构造方法。
不要为了部分功能而去继承
什么时候使用继承呢?
继承中类之间体现的是:”is a”的关系。
如:
Person
Student 学生是一个人
Teacher 老师是一个人
水果
菠萝 菠萝是一个水果
草莓 草莓是一个水果
白菜 它不能继承
继承中成员变量的关系
在子类方法中访问一个变量
首先在子类局部范围找
然后在子类成员范围找
最后在父类成员范围找(肯定不能访问到父类局部范围)
如果还是没有就报错。(不考虑父亲的父亲…)
如:
class Father {
int num = 10;
}
class Son extends Father {
int num2 = 20;
int num = 30;
public void show(){
int num = 40;
System.out.println(num);//40
System.out.println(num2);//20
}
}
class ExtendsDemo5 {
public static void main(String[] args) {
Son s = new Son();
s.show();
}
}
如果我要访问父类的成员方法用super关键字
this和super分别是什么,他们各自的应用场景是什么?
this是什么?this代表本类对应的引用
比如说吃饭这个方法它是由上帝来定义的,世界上所有的人来执行。吃饭这个行为发生的时候,主体就是在吃饭的这个人,也就是要有人执行吃饭这个行为。有时候我们需要在一个行为(方法)里,能够明确知道这个行为是谁来执行的,确切的说就是我要知道谁在吃饭。
public void eatSomthing(){
System.out.println( this.eat );
}
在我们定义的每一个方法里,都会有一个this关键字,这个this关键不由在那儿定义来决定的,而是由谁来执行的决定的。这是判断this的关键。
super是什么?super代表父类存储空间的标识(可以理解为父类引用)
调用父类的属性,一个类中如果有int x属性,如果其子类中也可以了int x属性的话,在子类中调用父类的x属性时,应使用 super.x = 6,表示该x是引用的父类的属性,而要表示子类中的x属性的话,使用this.x。
Java里的子类中用super调用父类构造函数时,调用的函数必须放在子类的第一条语句的位置
继承中构造方法的关系
子类中所有的构造方法默认都会访问父类中空参数的构造方法
为什么呢?
因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。
每一个构造方法的第一条语句默认都是:super()
如果父类中没有空参数构造方法,该怎么办呢?
1: 手动给父类中加上 空参数构造方法
2: a:在子类的构造方法中的第一行 写上 super(参数列表),访问父类中有参数的构造方法b:在子类的构造方法中的第一行 写上 this(参数列表),访问子类中其他的构造方法,然后在其他的构造方法中再去访问父类构造方法
继承中成员方法的关系
1:在父类中定义一个成员方法
2:在子类中定义一个成员方法和父类中成员方法名称不同,然后在测试类中通过子类对象去访问方法,发现方法名不同,访问子类的成员方法
3:在子类中再定义一个成员方法,和父类中的成员方法名称一致,然后继续访问。发现访问的是子类的成员方法。
4:如果我要访问父类的成员方法用super关键字即 super.父类的方法
方法重写概述
子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖,方法复写。
使用特点:
如果方法名不同,就调用对应的方法
如果方法名相同,最终使用的是子类自己的
方法重写的应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
方法重写的注意事项
父类中私有方法不能被重写
子类重写父类方法时,访问权限不能更低
父类静态方法,子类也必须通过静态方法进行重写。
举例:
class Father {
private void method(){
System.out.println("父类method方法");
}
public void function(){}
//void function(){}
//静态方法
public static void show(){ }
}
class Son extends Father {
public void method(){
//super.method();//访问父类中的method方法
//错误: method()可以在Father中访问private
System.out.println("子类method方法");
}
public void function(){}
//void function(){}//错误: Son中的function()无法覆盖Father中的function()
//静态方法
public static void show(){ }
//public void show(){ }//错误: Son中的show()无法覆盖Father中的show() ,被覆盖的方法为static
}
class ExtendsDemo11 {
public static void main(String[] args) {
//创建子类对象
Son s = new Son();
s.method();
}
}
1、方法重写和重载有什么区别?
答案:
重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。
重写Override表示子类中的方法可以与父类的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的更大,不能更少。如果父类的方法是private类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。
父类中成员private修饰,子类如何访问呢
用在父类中声明setXXX和getXXX方法
举例:
/*
学生案例和老师案例讲解
使用继承前
学生类
姓名,年龄,学号
睡觉()
学习(),打游戏()
(作业)老师类
姓名,年龄,工号
睡觉()
讲课(),做饭()
*/
/*
class 学生类 {
private String id;
private String 姓名;
private int 年龄;
//构造方法
public 学生类(){}
public 学生类(String id, String 姓名, int 年龄){
this.id = id;
this.姓名 = 姓名;
this.年龄 = 年龄;
}
//setXxx() getXxx()
//提供一个show方法,用来显示打印 学生类对象中的成员
public void show(){
System.out.println(id + "---" + 姓名 + "---" + 年龄);
}
}
class 老师类 {
}
*/
class Student {
//成员变量
private String id;//学号
private String name;//姓名
private int age;//年龄
//构造方法
public Student(){}
public Student(String id, String name, int age){
this.id = id;
this.name = name;
this.age = age;
}
//提供setXxx() getXxx();
public void setId(String id){
this.id = id;
}
public String getId(){
return id;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
//提供一个show方法,用来显示打印 学生类对象中的成员
public void show(){
System.out.println(id + "---" + name + "---" + age);
}
//睡觉()
public void sleep(){
System.out.println("睡觉");
}
//学习()
public void study(){
System.out.println("学习");
}
//打游戏()
public void playGame(){
System.out.println("英雄联盟");
}
}
class ExtendsDemo12 {
public static void main(String[] args) {
//创建对象
Student s = new Student("01", "李四", 20);
s.show();
s.sleep();
s.study();
s.playGame();
}
}
final关键字
final关键字是最终的意思,可以修饰类,成员变量,成员方法。
修饰类,类不能被继承
修饰变量,变量就变成了常量,只能被赋值一次
修饰方法,方法不能被重写
注:通过子类重写父类方法,来说明父类不能被人动的方法,也别动了。为了强制不能动,Java就提高了final关键字
http://blog.csdn.net/liu1pan2min3/article/details/44919569