1.面向对象:
概念:基于面向过程的思想,强调对象的创建,使用对象调用功能!
特点:1)更符合生活中的思想行为习惯,2)让复杂的事情简单化,3)从执行者变为指挥者(角色变化)
设计原理:不断的创建新对象,使用对象调用该对象的功能;
2.面向对象的 “ 三大特征 ”:
封装、继承、多态
3.面向对象------“ 封装 ”:
定义:将类中成员变量私有化,对外提供公共的访问方法(权限足够大)
“ private ”关键字:
1)private可以修饰一个类中的成员变量也可以修饰成员方法;
2)被private修饰的成员变量或者成员方法,只能在本类中访问,外界不可以访问;(保证数据的安全性)
“ this ”关键字:在Java中提供了一个this关键字,代表当前地址值引用;
为了区分成员变量和局部变量,谁调用了这个方法,那么就代表它的地址;
tihs.成员变量;---------------------访问本类成员变量;
this.成员方法;---------------------访问本类的成员方法;
this()访问无参构造方法;----访问本类的无参构造方法;
this()访问有参构造方法;-----访问本类的有参构造方法;
构造方法:
1)方法名和类名相同;
2)没有具体的返回值;
3)并且连void都没有;
格式:1) 权限修饰符 + 方法名(就是类名)(){ } ;-------------------无参构造;
2)权限修饰符 + 方法名(就是类名)(形式参数);-----------有参构造;
构造方法的要作用:主就是给该对象中的数据进行初始化;
构造方法的注意事项:
1)系统会默认提供一个无参构造方法
2)如果我们提供了一个有参构造,系统就不会提供无参构造方法,所以我们永远手动给出无参构造方法;
给构造方法中的成员变量赋值:采用的是setXXX(形参)和getXXX()方法;
举例:
//定义一个学生类
class Student{
//成员变量私有化
private String name ; //姓名
private int age; //年龄
//提供无参构造方法
public Student(){
}
//有参构造方法
public Student(String name,int age){
this.name = name;
this.age = age;
}
//提供公共的访问方法赋值 setXXX/getXXX方法 XXX对应的属性名称,并且赋值
//给名字赋值
public void setName(String name){
this.name = name;
}
//给年龄赋值
public void setAge(int a){
this.age = age;
}
//获取姓名
public String getName(){
return name ;
}
//获取年龄
public int getAge(){
return age ;
}
//其他的成员方法:
public void study(){
System.out.println("喜欢打篮球........") ;
}
}
//测试类
class StudentTest{
public static void main(String[] args){
//创建一个学生类
Student s = new Student() ; //name,age已经私有化了,只能通过公共方法赋值和获取值
//方法1:通过无参构造方法赋值
s.setname = "小明" ;
s.setage = 16 ;
System.out.println(s.getName()+"---"+s.getAge()) ;
s.study() ;
System.out.println("------------------");
//方式2:通过有参构造方法赋值
Student s1 = new Sudent("小明",16);
System.out.println(s1.getName()+"---"+s1.getAge()) ;
s1.study() ;
}
}
类和事物的关系:
类,class 是Java中的基本的单元,它用来描述一类事物
类,描述一组事物(现实世界事物)的属性和行为的集合!
事物 类
事物中属性 ------> 类中的成员变量
事物的行为 ------> 类中的成员方法
一个标准类的写法:
类{
1)属性私有化
2)提供对外的公共的setXXX(形式参数)/getXXX()方法
3)构造方法:
永远给出无参构造方法;
有参构造
}
成员方法的分类:(非静态的成员方法):
两种情况:
a:要么有返回值类型
1)有返回值类型,并且有参数
2)有返回值类型,没有参数
b: 要么没有具体返回值:void代替
1)没有返回值类型,带参
2)没有返回值类,不带参
关于静态static的特点:
1)被static修饰的变量/方法 都随着类的加载而加载
class xxx{} ----> 通过javac 编译xxx.java文件 --->编译没有问题(Java语法校验)
---->产生xxx.class文件
2)被static修饰的 优先于对象存在
3)被static修饰的可以被多个对象共用
4)被静态修饰的成员变量或者成员方法,可以被类名直接访问(推荐访问方式)
类名.成员方法
类名.成员方法()
4.面向对象-------“ 继承 ”:
定义:将其他类中的共性内容抽取出来,存放该独立的类,让独立的类和其他类产生一种关系,这种关系叫“继承关系”
格式:子类名 extends 父类名{ } ; extends:表示继承关系
继承的好处:
1)提高了代码的复用性(代码结构清晰);
2)提供了代码的维护性;
3)类和类产生的这种继承关系,是多态的前提条件;
继承的弊端:类与类之间的继承关系,存在一定的耦合性!
Java开发原则:低耦合,高内聚
耦合:尽量的一个类能完成的事情,不要和其他类产生过多的关系;
内聚:执行某件事情的动力
继承的特点:
1) 在Java语言中,类和类之间只支持单继承,不支持多继承
在其他语言中,是支持多继承的,语法格式:子类名 extends 父类名1,父类名2{}
2) 虽然不支持多继承,但是类与类之间是可以多层继承的;
什么时候可以用到继承?
答:当A类如果是B类的一种或者B类是A类的一种时,就存在继承关系;
继承中的成员关系:
成员变量
构造方法
成员方法
成员变量:
子类继承父类,如果子类中的成员变量名称和父类的成员变量名称不一致的情况:(比较简单) 分别访问;
子类继承父类,如果子类中的成员变量名称和父类的成员变量名称一致的情况:
执行流程:
1)现在子类的局部位置中找,如果找到了就使用它
2)如果局部位置中没有,在子类的成员位置中找,如果找到了,就使用!
3)如果找不到,就在父类的成员位置中找,如果找到了,就使用
4)如果还找不到,就报错了,说明访问了一个不存在的变量
遵循一个:"就近原则"
代码块的概念:
局部代码块:在方法定义中定义的“{ }” ,作用:限定局部变量的生命周期;
构造代码块:在类中成员位置中定义的 , 作用:在执行构造方法之前先执行的代码块;
静态代码块:在类中成员位置定义的static{}的代码块,作用:随着类的加载而加载,在{}里面的数据进行初始化,
整个{}优先于对象存在;
优先级的问题:
静态代码块的特点:随着了类的加载而加载,因为类的加载一次,静态代码块只执行一次
静态代码块 > 构造代码块 > 构造方法
继承中的注意事项:
1)子类继承父类,可以继承父类中所有的非私有的成员!
本身私有的成员变量/成员方法只能在本类中访问,外界不能访问的!,但是间接通过公共的访问方法来访问
2)子类继承父类,不继承父类构造方法,但是可以通过一个关键字来访问父类的构造方法
关于继承中构造方法的关系:
子类是不能继承父类的构造方法的,但是通过super()来访问父类的构造方法
1)在继承中,子类中所有的构造方法都默认访问父类的无参构造方法;
相当于子类的所有构造方法的第一句话:隐藏了super();
2)为什么,创建子类对象的时候,先执行父类的无参构造方法?
因为可能要用到父类中的数据,所以要先让父类中的数据进行初始化(构造方法),
父类初始化完毕了,然后才执行子类的构造方法(子类数据初始化)---->分层初始化
举例:
//父类
class Fu{
public int num = 10 ;
}
//子类
class Zi extends Fu{
public int num = 20 ;
public void show() {
int num = 30 ;
//补全代码
System.out.println(num);
System.out.println(this.num);
System.out.println(super.num);
}
}
//测试类
public class ExtendsTest {
public static void main(String[] args) {
//创建子类对象
Zi z = new Zi() ;
z.show();
}
}
方法重写:
在继承关系中,子类出现了和父类一摸一样的方法,这个是时候子类会将父类的该功能覆盖掉,这种现象称为:方法重写
在有的时候,不能将父类的功能覆盖掉,那么这个时候Java提供了一个关键字:final (状态修饰符)
final:最终的,无法更改的(状态修饰符),被final修饰的成员方法:该方法不能被子类重写!
final修饰的变量如果是基本类型,它的值不能再改变!
final修饰的变量如果是引用类型,它的堆内存地址值不能该改变!
方法重写(override)和方法重载(overload)的 区别?
方法重载:方法名相同,参数列表不同,与返回值无关!
参数列表不同:
1)形式参的数据类型是否相同
2)参数个数是否相同
方法重写:
@override 注解(JDK内置注解) 检查该方法是否是一个重写方法(重写父类的方法)
子类出现了和父类一模一样的方法声明:权限修饰符 返回值类型 方法名 形式参数都相同!
子类的该方法会将父类的方法覆盖掉!
举例:(猫狗案例)
//动物类
class Animal{
//
public void sleep() {
System.out.println("动物睡觉.....");
}
public void eat(){
System.out.println("动物吃东西....");
}
}
//定义猫类
class Cat extends Animal{
public void sleep() {
System.out.println("猫缩着睡觉.....");
}
public void eat(){
System.out.println("猫吃猫粮....");
}
}
//定义一个狗类
class Dog extends Animal{
public void sleep() {
System.out.println("狗站着睡觉.....");
}
public void eat(){
System.out.println("狗喝水....");
}
}
//定义一个动物工具类
class AnimalTool extends Animal{
//动物工具类
private AnimalTool() {
}
public static void dome(Animal a) {
a.eat();
a.sleep();
}
}
public class lianxiti2 {
public static void main(String[] args) {
Cat all = new Cat();
all.eat();
all.sleep();
System.out.println("-------------------");
Dog zee = new Dog();
zee.eat();
zee.sleep();
System.out.println("-------------------");
AnimalTool.dome(all);
AnimalTool.dome(zee);
}
}
5.面向对象-----“ 多态”:
定义:一个事物在不同时刻的体现(堆内存中对象形式)
多态的前提条件:
1)必须有继承关系 (继承的好处第三点作为多态的前提条件);
2)方法重写 ,子类继承父类,将父类的功能覆盖掉,使用子类最具体的功能;
3)父类引用指向子类对象
父类名 对象名 = new 子类名() ;(称为"向上转型");
多态的成员访问特点: Fu f = new Zi() ;
成员变量: 编译看左边,运行看左边;
成员方法: 编译看左边,运行看右边;
静态的成员方法: 编译看左,运行看左!(静态的算不上方法重写,跟类直接相关,随着类的加载而加载)
构造方法:存在继承关系(还是分层初始化),先让父类初始化,然后在是子类初始化;
多态的好处:
1)提高了代码的复用性(由继承来保证)
2)提高了代码的扩展性(有多态来保证)
多态的弊端:不能访问子类的特有功能
访问子类功能解决方案如下:
方案1):创建子类的具体对象来访问子类的特有功能!
代码实现角度来说没有任何问题,但是从内存角度考虑:创建一个新的对象,需要在堆内存中产生一个空间地址值,耗费空间!
方案2):
模拟向上转型的方式: 父类引用指向子类对象 Fu f = new Zi() 向上转型的格式
在使用多态的向下转型不当时,程序出现运行时期异常——ClassCastException:类转换异常属于运行时期异常!
举例:
//定义一个动物类
class Animal3{
public void eat() {
System.out.println("动物需要吃饭");
}
public void sleep() {
System.out.println("动物需要休息");
}
}
//定义一个子类
class Dog3 extends Animal3{
public void eat() {
System.out.println("狗吃狗粮");
}
public void sleep() {
System.out.println("狗卧着睡觉");
}
//特有功能
public void lookDoor() {
System.out.println("狗可以看门...");
}
}
//测试类
public class DuoTaiDemo4 {
public static void main(String[] args) {
//多态的格式:父类引用指向子类对象(向上转型)
Animal3 a = new Dog3() ; //狗是动物 (内存中是狗)
a.eat();
a.sleep();
//a.lookDoor() ;
//方案1)创建子类的具体对象来访问子类的特有功能!
/*Dog3 d = new Dog3() ;
d.lookDoor();*/
//向下转型:
//子类名 对象名 = (子类名)父类的引用;
Dog3 d = (Dog3)a; //狗是狗 (还原成狗)
d.lookDoor();
}
}