一.面向对象:
1. 对象:在面向对象程序设计中,我们将问题空间中的元素以及他们在方案空间中的的表示物称作对象(object)
所有的东西都是对象。
程序是一大堆对象的集合,他们通过消息传递,各个对象之间知道要做些什么。
每个对象都分配有自己的存储空间,可容纳其他对象。
每个对象都有一个类型。
同一类的所有对象能接收相同的消息。
-----而所有的编程语言的最终目的是提供一种抽象方法----
面向对象分析:学生类 老师类
学生类:
--成员属性:定义方式:数据类型 变量名;后面可以有初始值,但一般不用写。
学员编号:
姓名:
性别:
年龄:
分数:
--成员方法:
show();
class Student
{
//成员属性:
String stuNo;//学员编号
String stuName;//学员姓名
char stuSex;//学员性别
int age;//学员年龄
double score;//分数
//成员方法
//之前的方式:
// public static void show(){
// }
//现在的方式:省略掉"修饰符"部分
void show(){
System.out.println("大家好,我是传智播客的一名学生");
}
}
class Demo
{
public static void main(String[] args)
{
//使用Student类:
//1.实例化一个Student对象:数据类型 变量名 = new 数据类型();
// int[] arr = new int[3];
Student stu = new Student();//只有new之后,才会产生内存空间,才可以访问成员属性和方法;
System.out.println("----实例化Student对象后直接访问成员属性-----");
System.out.println(stu.stuNo);
System.out.println(stu.stuName);
System.out.println(stu.age);
System.out.println(stu.stuSex);
System.out.println(stu.score);
//2.设置成员属性:变量名.属性名 = 值;
stu.stuName = "张三";
stu.score = 88;
//3.访问成员属性:变量名.属性名
System.out.println("学员姓名:" + stu.stuName);
System.out.println("分数:" + stu.score);
//我想记录第二个学生:再new一个Student对象
Student stu2 = new Student();
stu2.stuName = "李四";
stu2.score = 99;
System.out.println("学员姓名:" + stu2.stuName);
System.out.println("分数:" + stu2.score);
//调用成员方法:变量名.方法名([实参]);
stu2.show();
}
2. 成员变量和局部变量的区别:
1.定义的位置不同:
1).局部变量:定义在某个方法体内;或者某个代码块内;
2).成员变量:定义在"类体"中
2.在内存中的位置不同:
1).局部变量(基本数据类型):在"栈"中;
2).成员变量:在"堆"中;
3.生命周期:
1).局部变量(基本数据类型):当所在代码块执行完毕,存储在栈中的局部变量会立即消失;
2).成员变量:作为垃圾,不会立即清除,后期会被"垃圾回收器"不定期清理;
4.初始化方式不一样:
1).局部变量:必须显示的手动为其指定初始值;否则不能访问其值;
2).成员变量:当分配堆内存时会被自动初始化。
整数:0,浮点:0.0.,字符:\u0000,布尔:false,Str
二..面向对象的三大基本特征是:封装、继承、多态
1).封装
对象要有一个明确的边界;边界的划分(对象各司其职、对象的粒度、对象的可重用性)
具体来说:
1.属性: 私有 private(提供set和get方法)但封装 也不一要有private
2.方法: 公开或私有public/private
3.方法声明 --> 公开
方法实现 --> 隐藏
实现改变时,对对象的使用者没有影响。
1.2.)this关键字的概念:
1.成员方法是可以访问成员属性的;
2.对于一个类中的"成员属性",是每个对象都拥有一份独立存储空间;
对于"成员方法",是所有对象共享一个"方法空间";
3.this是一个隐式的变量;任何类都有的;
4.this是在实例化此类对象时,会被赋值成当前对象的地址;
5.一般情况下,this 是Java内部隐式使用的。
6.但是,有些时候我们需要必须显示的使用:
1).局部变量覆盖成员变量时,如果要访问成员变量,可以使用:this.成员变量名
1.3)构造方法:
1.构造方法,就是当实例化一个对象时,会调用的一个方法;
2.我们之前没有写过构造方法,系统给我自动添加一个什么都不做的构造方法;
3.构造方法的写法:
[访问修饰符] 构造方法名([形参列表]){
}
注意:
1.访问修饰符,我们现在先不写;
2.不可以指定"返回值类型"甚至是void;
3.构造方法名要跟类名完全相同,大小写要一致;
4.形参列表:可以没有。如果有,跟方法的形参列表定义一样;
4.构造方法是在每次"实例化此类对象时"被调用一次,之后将不会再次被调用;
5.构造方法的作用:
1).由于它是在实例化此类对象时被调用,所以一般做一些初始化的工作。
例如:初始化成员变量;
6.构造方法可以没有,系统会自动添加一个什么都不做的构造方法;
构造方法也可以有一个,那么意味着此时构造此类的对象只能通过这一种方式;
构造方法可以有多个,那么意味着可以有多重方式去构造此类对象。这叫:构造方法的重载。方法名一样,参数列表不完全相同;
7.如果我们编写了构造方法,那么系统将不会再添加默认的构造方法;
8.尤其注意:如果一个类,只有一个构造方法,而且需要参数,那么,实例化此类的对象时,就必须拿着参数调用这个构造方法,别无他途。
1.4) static关键字:
1 .为什么要使用static关键字?
对于一些已经有固定值的变量,每次实例化对象都会产生空间,
其值基本是固定了,为了防止过多的存储此变量造成空间浪费,我们
可以将此变量声明为static(静态)。
2.static可以修饰"成员属性"和"成员方法":
注意事项:
1.静态方法只能访问静态成员;
2.非静态方法,可以访问静态和非静态成员
3.静态成员变量和普通成员变量的区别:
1.所属不同
静态成员变量:所属于类;
普通成员变量:所属与对象;
2.内存中位置不同
静态成员变量:方法区的静态存储区;
普通成员变量:堆空间;
3.内存出现时间不同
静态成员变量:第一次使用该"类"时,会被分配空间;
普通成员变量:当new一个此类对象时;
4.调用不同
静态成员变 量:可以通过"类名"和"对象名"调用;
普通成员变量:只能通过"对象名"调用;
1.5 .代码块:
1.它可以定义在某个方法内(局部代码块),也可以定义在类体中(构造代码块);
2.当它定义在类体中时,当每次实例化此类的对象时,会被执行;
如果此类同时有构造方法,那么"先执行代码块","后执行构造方法";
3.代码块的作用同构造方法,一般用于做一些初始化的工作。例如:初始化成员变量;
虽然同构造方法的作用一样,但代码块不能接收参数。所以它没有构造方法使用灵活;
4.静态代码块:
1).在代码块之前添加static关键字;
2).它在第一次实例化此类的对象时,或者第一次访问类中的静态成员时,只执行一次,之后再实例化此类对象时将不再被执行;
3).如果一个类同时存在"代码块","构造方法","静态代码块",执行顺序:
1.静态代码块;(第一次实例化此类对象时会被执行一次)
2.代码块;
3.构造方法;
4).静态代码块一般用于初始化静态成员;
注意:如果静态代码块访问静态成员变量,那么此变量一定定义在静态代码块之前。否则编译错误;
2) 继承 共性放到父类,特性放到子类;父类 --> 子类,其实就是特殊 --> 一般
1.关键字: extends 例如:Dog extends Animal{}
2.java中一个类最多只能有一个直接的父类,即单继承(具有简单性、树形结构),
C++中是单继承
java中要实现多继承,通过接口来实现。
3.父类中所有属性和方法都能继承给子类;父类中的私有方法不能继承给子类。
4.
访问权限 继承
private 本类内部 不能继承
default 本类+同包 同包子类可以继承
protected 本类+同包+不同子包 可以继承
public 公开 可以继承
5.构造对象过程
(1)分配空间
(2)递归地构造父类对象
a. 父类 初始化属性
b. 父类 构造方法
(3)初始化属性
(4)调用构造方法
6.super
用法:
super() 调用父类的构造方法,只能出现在构造方法的第一行
super.方法名 super表示父类的对象,通过它去调用父类的方法
注意:在写类的时候,一定要写默认无参的构造方法,如果一个构造方法的
第一句既不是this(),也不是super()时,那么就会在这里隐含的调用
他的父类的无参的构造方法,即隐含的有super()。
2.1 Java继承的特点:
1.一个类,只能继承自一个类,不能同时继承自多个类:
如果多个父类有相同的方法,那么子类继承后,不知道去执行哪一个;
class A{
void show(){
}
}
class B{
void show(){
}
}
//下面的代码错误,不能同时继承自多个类;
class C extends A,B{
}
2.在Java中可以多级继承:
class A{
void show(){
}
}
class B extends A{
void fun(){
}
}
class C extends B{
void m(){
}
}
2.2 super和this的区别:
1.this始终是指向本类的成员:
1).访问本类的成员;
class A{
int num = 10;
void f1(){
System.out.println("num = " + this.num);
this.f2();//调用本类的f2()方法
}
void f2(){
}
}
2).在本类的构造方法中,调用本类其它的构造方法;
class A{
A(){
System.out.println("a1");
}
A(int b){
this();//调用此类无参的构造方法;它必须是这个构造方法的第一条有效语句;
System.out.println("a2");
}
}
main(){
A a = new A(2);
}
2.super始终是指向父类的空间:
1.通过super可以访问父类的成员:
2.可以调用父类的构造方法;
3.在子类中的构造方法,默认情况下会在第一行自动添加一句:super();//调用父类的无参的构造方法;
4.注意:
如果父类没有无参的构造方法,那么子类的构造方法中,就必须使用super()去显示的去调用父类的某个
带参的构造方法;
5.在子类的构造方法中调用父类的构造方法使用super().这里也要求super()必须是这个构造方法的第一句话;
6.在子类的构造方法中,不能即使用this()又使用super();因为都需要在第一句话;
2.3 ) 继承中成员变量和成员方法的关系:
1.成员变量:子类中可以定义跟父类相同的成员变量,此时将覆盖父类的成员变量;
发生覆盖时,如果在子类中访问此成员变量,访问的将是子类的。
2.成员方法:子类中可以定义跟父类"一模一样"的成员方法,此时将覆盖父类中的同名的成员方法。这叫:方法重写;
方法重写的规则:什么是一模一样?
1.要求返回值类型、方法名、形参列表都必须一致;
返回值类型(一致) 方法名(一致) 形参列表(不一致):编译通过。效果"相当于"重载
返回值类型(不一致) 方法名(一致) 形参列表(一致):编译错误。
2.关于访问修饰符:子类必须拥有比父类更宽的访问修饰符;
2.4)方法重写的注意事项:
1.父类中私有的方法不能被重写;
2.子类重写父类方法时,访问权限不能更低:private,(默认),protected,public
3.父类静态方法,子类也必须通过静态方法进行重写。
2.5) .重写和重载的区别:
1.重写:Override;存在子父类继承关系的情况下,子类重写父类的方法。
子类定义跟父类相同返回值类型、方法名、形参列表的方法;
重载:Overload;在一个类中。
定义多个同名的方法,但形参列表不完全相同。
跟返回值类型无关;
跟形参名无关;
2.6)this和super的区别:
this: 1.始终指向当前对象的引用,
2.访问当前对象的成员属性、成员方法、构造方法;
3.查找是从当前类中查找,如果没有,向父类查找;
4.必须使用this的场景:
1).局部变量覆盖成员变量:使用this去访问成员变量
2).一个构造方法调用另一个构造方法,必须使用this()去调用;
必须放在此构造方法的第一句话;
super: 1.始终指向父类对象的引用:
2.访问父类对象的成员属性、成员方法、构造方法;
3.必须使用super的场景:
1).子类的成员变量覆盖父类的成员变量,使用super去访问父类的成员变量;
2).父类没有无参构造方法,子类的构造方法必须
显示的使用super()去调用父类带参的构造方法;必须放在此构造方法的第一句话;
2.7)使用final:
1.final:最终的;
2.它可以修饰:
1).成员变量,局部变量:此变量拥有最终的值,其值不能被改变
2).成员方法:最终的方法,不能被重写;
3).类:最终的类,不能被继承;
3)..多态
运行时多态。
子类的对象放在父类的引用中,例如 Animal a=new Dog,子类对象当父类对象来使用。
1.多态原则:
(1)对象类型不变
(2)只能用引用调用其引用类型中定义的方法
(3)运行时,根据对象的实际类型去找子类覆盖之后的方法
例子:
有Animal类中有eat()和sleep()两个方法,sleep()中睡8小时;子类Dog中有
eat()方法,sleep()方法中睡6小时,还有wangwang()方法。
现创建Animal a=new Dog(); 不能调用a.wangwang(),调用a.sleep()输出睡6小时。
2.对象的强制转换
格式: 引用 instanceof 类型
引用所指的对象是否鱼类相符,返回值boolean值。
用法:
Animal a=new Cat();
if(a instanceof Dog)
{
Dog d=(Dog)a;
d.wangwang();
}
说明:如果只有Dog d=(Dog)a;运行时错误,因为a是Cat而不是Dog (多态原则第一条)
3.多态的灵活变换
(1)用于参数列表上:
public void m(A a){} 可以用A类的任何子类对象作为参数
(2)用在返回值上:
public A m(){} 这个方法可能返回A类的任何子类对象
3.1)多态中成员的访问特点:
注意:当多态时,通过父类的引用去访问的成员,在父类中一定要有,否则,编译不通过;
也就是,多态时,父类的引用不能访问子类自有的内容;
1.成员变量:当子类的成员变量覆盖父类的成员变量时,通过父类的引用去访问时,打印的仍然是父类的;
编译看左边,运行看左边;
2.成员方法:当子类的成员方法覆盖父类的成员方法时,通过父类的引用去访问时,运行的是子类的方法;
编译看左边,运行看右边;
3.静态成员:当子类的静态成员方法覆盖父类的静态成员方法时,通过父类的引用去访问时,运行的是父类的;
编译看左边,运行看左边;
3.2)抽象类:
1.当所有子类将父类的方法重写后,父类的方法的定义就没有意义了;
2.就父类本身来讲,应用时,一般不会实例化一个"父类对象";
3.所以"父类"经常会成为一种"概念性的抽象",它的作用似乎成了被其它类继承的,代码重用;
4.此时,我们可以将方法定义为抽象的方法,没有方法体。使用关键字:abstract
5.如果一个类中包含了一个"抽象方法",那么这个类也必须是抽象的。
6.如果父类是抽象类,子类仍然使用extends去继承;仍然是单继承;
7.如果一个类继承了一个抽象类,那么此类必须要重写(实现)抽象类中的所有抽象方法;
8.一个抽象类,不能被"实例化",就是用来被其它类继承的;
abstract class Person
{
abstract void show();
}
class Student extends Person
{
void show(){
System.out.println("大家好,我是一名学生,我骄傲!!");
}
}
class Teacher extends Person
{
void show(){
System.out.println("大家好,我是一名教师,我骄傲!!");
}
}
class Demo
{
public static void main(String[] args)
{
Student stu = new Student();
stu.show();
Teacher tea = new Teacher();
tea.show();
}
}