一、面向对象(继)
1.this关键字
---------->代表当前类对象的地址值引用
目的:为了区分局部变量隐藏了成员变量
格式:
this.成员变量 = 局部变量;
例:
public void setName(String name){//局部变量,需要传入实际参数
this.name = name ; //成员变量= 局部变量
}
2.局部变量和成员变量
区别:
1)书写位置不同
成员变量:类中,方法外
局部变量:方法定义中,或者方法声明上
2)内存中位置不同
成员变量:堆内存中,和对象有关系
局部变量:栈内存中,和方法有关系
3)生命周期不同
成员变量:随着对象的创建而存在,随着对象的创建完毕等待jvm的垃圾器空闲时回收而消失
局部变量:随着方法的调用而存在,随着方法的调用而消失;
4)初始值不同
成员变量:是可以不初始化的,需要通过对象来赋值,存在默认初始化
局部变量:必须在使用之前初始化,否则报错
附:
什么时候把一个定义为成员变量的时机?
如果一个类能够描述这个事物的属性,必须为定义成员变量;否则都定义为局部变量
3.匿名对象
---------->没有名字的对象
好处:节省空间
匿名对象可以作为参数传递,创建完毕之后,没有栈内存指向,所以使用完毕立即被GC(垃圾回收器回收)
一般情况:匿名对象使用一次即可,这样不需要过多的开辟堆内存空间,直接被回收
格式:
new 类名();
匿名对象调用方法:
new 类名().成员方法名();
例: //使用匿名对象new 类名()
//new 类名().成员方法名() ; //调用自己方法
sd.method(new Student());
4.构造方法(就是一种方法)
1)这个方法,方法名和类名相同 2)这个方法,连void都没有 3)构造方法是可以重载的;(无参构造方法;有参构造方法)
目的:为了类的成员相关的数据进行初始化
系统默认初始化
显示初始化
注意事项:
当一个类中没有任何构造方法(无参/有参),系统会默认提供无参构造方法;
但如果提供有参构造方法,系统就不会再提供无参构造方法,无参构造就会报错;
一个标准类写法:
成员变量私有化
提供对外的公共访问方法,setXXX()/getXXX()
提供无参构造/有参构造方法(根据需求判断)
小结:
1)方法的形式参数是基本类型,调用方法的时候实际参数需传递对应数据值即可2)方法的形式参数是引用类型:数组,类,接口。实际参数在进行传递需要传递当前数组对象/类的对象/接口的对象
new :创建实例(堆内存开辟空间:空间地址值)
5.static关键字
本身含义:共有,共享的意思
static特点:
1)被静态修饰的随着类的加载而加载,优先与对象存在2)不能和this共存
3)本身含义就是共享,共用;可以有多个对象共享共用
4)被静态修饰的成员变量或者成员方法(静态变量/静态方法)
调用方式:
可以使用对象名来访问
对于系统来说jvm静态的东西:变量/方法
都是类名直接访问
类名.变量名; 类名.方法名();
静态的使用场景适用范围(静态只能访问静态):
1)静态中只能访问静态变量;
2)静态方法只能调用静态方法;
3)非静态方法皆可以访文静态的东西也可以访问非静态的东西
例:
class Demo{
int num = 10 ;//非静态的
static int num2 = 20 ;//静态的
//非静态的成员方法
public void show(){ //非静态既可以调用静态/非静态方法
System.out.println("show Demo");
method(); //调用静态方法
System.out.println(num2) ;
System.out.println(num);
}
//静态的成员方法
public static void method(){ //静态只能访问静态
System.out.println("method Demo");
// show() ;
System.out.println(num2);
// System.out.println(num);//num是静态的
}
}
//测试类
public class StaticDemo {
public static void main(String[] args) {
//访问num和num2 ---都可以使用对象来访问
Demo d = new Demo() ;
System.out.println(d.num) ;//10
// System.out.println(d.num2) ;//20 //不推荐 对象名.变量名 num2静态的---属于类成员
System.out.println(Demo.num2);//类名直接访问;
System.out.println("-------------------------------------") ;
//调用show()
d.show();
//d.method() ; //对象名.静态方法名() 可以的,idea不会提示 ;不推荐,静态方法随着类加载而加载
//类名直接访问;
Demo.method() ;
System.out.println("---------------------");
int result = add(10, 20); //main方法是静态的,main中调用其他方法必须静态,否则报错;
System.out.println(result);
}
//自定义了一个方法
public static int add(int a,int b){
return a+b ;
}
}
6.代码块----->使用{}括起来的内容
分类:
1)局部代码块:就是在方法中使用{}
{} ------>作用:限定局部变量的生命周期
2)构造代码块:在类的成员位置定义的{}
特点:在执行构造方法前,如果类中有构造代码块,优先执行构造代码块
作用:可以给类的成员的数据进行初始化
3)静态代码块:类加载一次,静态代码块也就执行一次
格式:
static{ //跟静态相关的都和类有关系,随着类加载而加载
********
}
优先级:静态代码块>构造代码块>构造方法(无参方法>有参方法)
例:
//定义一个Code类
class Code{
//静态代码块
static{
int x = 1000 ;
System.out.println(x );
}
//无参构造方法
public Code(){
System.out.println("code...");
}
//构造代码块:类的成员位置
{
int x = 100 ;
System.out.println(x);
}
//构造代码块
{
int y = 200 ;
System.out.println(y) ;
}
//有参构造方法
public Code(String name){
System.out.println("code"+name);
}
//静态代码块
static{
int y = 2000 ;
System.out.println(y);
}
}
7.继承
将多个类的共性内存抽取出来,放在一个独立的类中,让这个独立的类和其他类产生一种关系“继承”(关键字:extends)
格式:
class 父类名{
共性内容:姓名,年龄.....
提供公共的访问方法setXXX()/getXXX()
}
class 子类名 extends 父类名{
}
好处:
1)可以提高代码复用性
2)可以提高代码的维护性,后期便于维护,针对子类和父类进行维护(子父关系明确)
3)类与类产生的继承关系,是“多态”的前提条件
附:
在Java中有一个开发原则 "低耦合,高内聚"(以后所有的Java设计模式都需要遵循这一个原则) 耦合性:开发中是永远避免不了,可以降低(耦合:类和类的关系) 内聚性:指的是某个类完成某个功能的一种能力; 尽量不要产生继承关系来完成一个功能,一 个类能完成一个类完成; 低耦合:降低耦合性,减少类和类的关系;
继承的特点:
1)在Java语言不支持中,类和类的关系是一种继承关系,这个继承关系只能支持“单继承”不支持多继承;
2)类和类的关系不支持多继承,但是可以层层继承(多层继承);
例:
//定义父类
class GrandFather{
public void method(){
System.out.println("我是爷爷...");
}
}
//定义父类
class Father extends GrandFather{
public void show(){
System.out.println("我是爸爸...");
}
}
//父类
//class Mother{}
//子类
//class Son extends Father,Mother{} //子类不能继承多个父类,多继承语法不支持
class Son extends Father{
//自己的特有功能
public void playGame(){
System.out.println("会玩游戏");
}
}
public class ExtendsDemo2 {
public static void main(String[] args) {
//创建Son类对象
Son s = new Son() ;
s.show(); //访问父亲的方法
s.method();//访问爷爷的方法(method方法间接继承过来)
s.playGame(); //访问自己的方法
}
}
注意事项:
1)子类继承父类对于非私有的成员,可以直接继承过来,但是如果是私有成员,它可以通过公共的访问;
2)被私有修饰的东西(成员变量/成员方法),只能在当前类访问的;
在继承关系中,构造方法的访问问题:
子类继承父类,子类的所有构造方法都默认访问父类的无参构造方法;
为什么?子类继承父类,会用到父类的数据,需要让父类先进初始化;
面试题:
如果一个父类存在有参构造方法,没有无参构造方法,子类的所有构造会出现什么问题?出现了问题,怎么解决?
出现的问题:子类所有方法报错 -----> 子类继承父类,子类的所有构造方法都默认访问父类的无参构造方法
方案1:
手动给出无参构造方法
方案2:假设,人家现在就不需要让你给出父类的无参构造方法,就需要让子类的构造方法,显示的访问 父类的有参构造方法
----要使用关键字 super:代表父类空间标识(代表的父类对象的地址值引用!)
super() :访问父类的无参构造方法
super(xxx) :访问父类的有参构造方法
这些super一定是在子类构造方法中的第一句话
方案3:保证子类的所有的构造方法某一个构造方法,让父类初始化完毕即可;
先通过子类的无参构造方法里面---this(xxx):访问本类(子类)有参构造方法
在子类的有参构造方法的第一话:让父类初始化 super(xxx):间接访问父类的有参构造方法
附: this和super的区别
this:代表的当前类对象的地址值引用 super:代表的父类的空间标识(父类的对象的地址值引用)this.变量名 :访问本类的成员变量 super.变量名:访问的父类的成员变量this.方法名():访问本类的成员方法 super.方法名():访问父类的成员方法
this():访问本类无参构造方法 this(xxx):访问的是本类的有参构造方法 super():访问父类的无参构造方法 super(xxx):访问的父类的有参构造方法
子类继承父类,关于成员方法的访问
情况1:子类和父类的成员方法名称不一致,比较简单,分别调用即可;
情况2:子类和父类的成员方法一模一样:权限修饰符,返回值类型,参数列表都一样
如何访问:
1)先在子类的局部位置找,有没有这个变量,有就使用;
2)如果没有,在子类成员位置中找,有没有这个变量,有就使用;
3)如果子类的成员位置也没有,然后会在父类的成员位置找,有没有这个变量,有就使用;
4)如果父类的成员位置都没有,报错(前提:这个父类没有它的父类了),说明整个子父类中都没有变量;
子类将父类的方法覆盖了---->方法重写:Override---->子类在父类的基础上,将父类的覆盖了,使用自己的功能;
8.final关键字
最终的,无法更改的,状态修饰符 ,被final修饰的成员方法,不能被重写,保证父类的方法安全性!
特点:
1)可以修饰类,但该类不能被继承
2)可以修饰变量,此时这个变量是一个“常量”,常驻常驻常量
自定义常量:在开发中:
定义一个int类型的
public static final 数据类型 xxx = 值;
class Demo{
public static final int x = 100 ; // 自定义常量: 编译时期常量,不需要加载;jvm检查语法即可
//后期常用类:基本类型 int---> 自动提升 Integer 类
public static final Integer i = new Integer(100) ; 运行时期常量,因为jvm需要加载Integer类
}
类名访问:
Demo.x
Demo.i
3)final修饰成员方法,此时这个方法不能被子类重写,目的我了保证方法中某些数据的安全性
例:
class Fu{
// public void function(){
public final void function(){
System.out.println("这个是绝密文件,任何不得更改");
}
}
//子类继承父类
class Zi extends Fu{
/* public void function(){
System.out.println("这是一堆垃圾...");
}*/
}
//测试类
public class FinalDemo {
public static void main(String[] args) {
//创建子类对象
Zi z = new Zi() ;
z.function();
}
}
9.多态
宏观角度(现实中):一个事物在不同时刻体现的不同形态
微观角度(内存中变化):具有对象在内存中的变化(对象在不同时刻的类型)
※多态的前提条件:
1)必须有继承关系(类与类),没有继承关系,不谈多态
2)必须存在方法重写,子类部分功能将父类的功能进行覆盖、重写,子类使用自己的功能体现
3)必须在父类引用指向子类对象
固定格式: class Fu{ } class Zi extends Fu{ } 父类名 对象名 = new 子类名() ; //向上转型:使用的父亲的东西 Fu fu = new Zi() ; //父类引用指向 子类对象
※多态的成员访问特点:
格式: 父类名 对象名 = new 子类名() ;
1)成员变量: 编译看左,运行看右;
2)成员方法:非静态
编译看左,运行看右;(因为子类重写了父类功能)
静态方法:即使子类出现了和父类一样的静态方法,不算重写,因为静态方法都是自己类相关的类成员
3)构造方法:多态的前提条件,有继承关系,跟继承一样,分层初始化
先执行父类的构造方法,然后再是子类的构造方法
例:
class Animal{
int age = 50 ;
public Animal(){
System.out.println("Animal的无参构造方法");
}
public void eat(){
System.out.println("动物饿了都需要吃饭");
}
public void sleep(){
System.out.println("动物困了就需要休息");
}
//父类的静态方法
public static void show(){
System.out.println("show Animal");
}
}
//猫类
class Cat extends Animal{
int age = 20 ;
public Cat(){
System.out.println("Cat的无参构造方法");
}
//将eat和sleep()具体体现,应该重写父类的方法
public static void show(){
System.out.println("show Cat");
}
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫躺着睡");
}
}
//狗类
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头...");
}
@Override
public void sleep() {
System.out.println("狗侧着睡...");
}
}
//测试类
public class DuoTaiDemo {
public static void main(String[] args) {
//多态进行测试:
//父类引用指向 子类对象 :固定格式
//父类名 对象名 =new 子类名() ;
Animal a = new Cat() ; //堆内存存储的猫 猫是动物
System.out.println(a.age) ;// 编译看左,运行看左 ;
a.eat(); //编译看左,运行看右 (前提存在重写)
a.sleep();编译看左,运行看右 (前提存在重写)
//调用静态show
//a.show() ; //编译看左,运行看左---show方法是静态,不推荐使用对象访问,类名访问
Animal.show();
Cat.show();
/* Animal a2 = new Dog() ; //狗是动物 堆内存中存储的是狗
a2.eat();
a2.sleep();*/
}
}
多态的弊端:
1)有继承关系
2)有重写
3)有父类引用指向子类对象(无法调用子类特有功能) ------> Fu f = new Zi();
解决方案:
方案一:创建自己的子类对象
子类名 对象名 = new 子类名() ; 方案1不好地方:本身Fu fu = new Zi() ;已经开辟堆内存空间了, Zi zi = new Zi();又要在堆内存开辟空间,消耗内存空间比较大;方案二:多态的第三个前提条件:父类引用指向子类对象
将父类的引用强制为子类的引用:
向下转型 前提必须向上转型Fu fu = new Zi() ; Zi z = (Zi)fu ; //强转的语法 这样的好处:节省内存空间
多态的好处:
1)提高代码的复用性,由继承保证的 2)提高代码的扩展性,由多态保证 : 父类引用指向子类对象
关于面向对象中牵扯关系问题:
Java中最基本的单元是类
类和类:继承关系 extends,Java语言中只支持单继承,不支持多继承,但是可以多层继承
类和接口: 实现关系 implements;一个类继承另一个类的同时,可以实现多个接口
接口和接口:继承关系:extends 不仅支持单继承,也可以多继承
二、抽象(关键字:abstract)
在一个类中,如果有抽象方法,这个类必须为抽象
抽象特点:
1)不能实例化(不能创建对象);
2)必须强制子类完成事件:必须将抽象方法重写;
抽象类的子类:
如果子类是抽象类,那这个子类将会没有任何意义(抽象new不了对象)(前提是这个子类没有子类);
研究的抽象类的子类一定会有一个具体类,这个时候通过具体类才能创建对象;
抽象的父类名 对象名 = new 具体的子类名(); 抽象类多态
抽象类的特点:
成员变量:抽象类的成员变量既可以有变量,也可以是自定义常量被final
成员方法:抽象类中既可以有抽象方法也可以有非抽象方法
构造方法: 可以定义无参/有参方法...
存在抽象类多态,、有继承关系、初始化的时候,构造方法---->分层化处理------>先父类初始化,再子类初始化
面试题: 1)如果有一个类没有任何的抽象方法,还要将这个类定义为抽象类的意义? 意义:意义就是不能让它new 2)它如何实例化? 肯定有具体的子类,进行抽象类多态来操作...
面试题:
abstract和哪些关键字冲突:
1)private关键字冲突:因为被private私有的成员方法只能在本类访问,而abstract修饰的成员方法 必须强制子类重写,已经超出来的当前类的范围
2)final关键字冲突:final修的成员方法,不能被重写;而抽象方法强制子类必须重写;
3)static关键字冲突:abstract修饰的方法必须被子类重写,而static修饰的方法,算不上抽象,直接跟类相关的;
abstract应用范围:
定义在类上---抽象类
定义在方法上----抽象方法
public abstract 返回值类型 方法名(空参/带参...) ;
abstract 返回值类型 方法/名(空参带参...) ;
附:
子类继承父类,子类重写父类的抽象方法,必须保证访问权限足够大,要么加public要么跟父类的方法保持一致!
三、接口(关键字:interface)
体现事物本身以外的额外功能,需要事物要对接口的功能要进行实现,才具备接口的定义
格式:
interface 接口名{ //命名规范和类名命名一样,见名知意 "大驼峰命名法"
只能为抽象方法
}
接口的子类----"子实现类"
实现
class 子类名 implements 接口名{
}
接口比抽象类还抽象----> 特点:不能实例化
如何实例化:
接口通过它的子实现类进行实例化(前提,这个类实现 implements 接口)
class 子实现类名 implements 接口名{ //实现
}
实际开发中:接口的子实现类名的命名---> 接口名的后面+Impl:表示是接口的实现类
接口的成员特点:
1)成员变量:只能是常量,存在默认修饰符 :public static final
2)成员方法:只能是抽象方法,存在默认修饰符 public abstract
3)构造方法:没有构造方法的---通过子实现类的构造方法来实例化
接口本身意义:对外暴露这些功能,让子实现类实现
interface Inter{
int num = 20 ;
void show() ;
}
class InterImpl implements Inter{//实现类必须实现接口的抽象方法,否则报错
@Override
public void show() {
System.out.println("show InterImpl");
}
}
public class InterfaceDemo {
public static void main(String[] args) {
Inter inter = new InterImpl() ;
System.out.println(inter.num); //编译看左,运行看左
System.out.println(Inter.num) ; //接口比抽象类还抽象 之前:类名.变量名; 变量被static修饰
//接口名.变量名 ; 变量被static修饰
}
}
卡一个数字!!