Java基础笔记2——方法和面向对象

Java基础笔记2
六、方法
将要重复使用的逻辑或者是代码提取到一个新的结构——方法。
修饰符 返回值类型 方法名(参数列表){
方法体;
return 返回值;
}
无返回值的方法用void定义,void方法也可以写return语句,但只能写为return;用于规避掉一些非法数据。
方法的定义过程需要明确返回值类型,明确参数。
明确参数类型——根据方法的执行结果的类型来确定。
定义方法的时候在()内定义的参数称为形式参数,简称形参。调用方法的时候传入的数据称之为实参。
方法签名:方法名+参数列表,例method(int a)
同一个类中不能存在方法签名相同的方法。
方法的传参
形参:定义方法的时候()定义的变量
实参:调用方法的时候传入的数据
对于基本类型而言,传参传递的是实际值,所以在另一个方法中改变这个参数的值不会影响原来方法的数据。
对于引用类型而言,传参传递的是地址。如果地址不发生改变,则影响原来方法中的对象;如果地址放生改变,则不影响原来的对象。
可变参数
本质上是一个数组,可以传入任意个数的参数。
public static int sum(int … ns){ //…代表0或多个参数
int sum=0;
for(int n:ns){ //遍历参数,求和
sum+=n;
}
可变参数可以直接传入一个数组。
int[] num={1,2,3,4,5,6,7,8};
sum(num); //调用sum方法
注意:在一个方法里只可以有一个可变参数,只能用一次,且必须在参数列表最后一个位置出现。
public static int sum(int n3,int … ns){
int sum=0;
for(int n:ns){
sum+=n;
}
return sum*n3;
方法重载
在同一个类中,定义多个方法名一致而参数列表不同(参数个数或者对应位置上的参数类型不一样)的方法。
方法有歧义的不能构成重载。如add(int i,int j)和add(int a,int b),只是形参变量名不一样而已,实际方法签名一致。
所谓参数列表不同实际上是看每一位上的参数类型是否不同或者参数个数是否不同。和修饰符、返回值类型、异常没有关系。
参数类型不一样,排序不一样,可以构成方法重载,如下①②两种方法。
①add(int i,double j)
②add(double j,int i)
根据实参类型确认调用的方法,就近原则——优先调用参数类型最符合的方法。
方法的递归
定义:在方法中调用自己本身。
应用:利用递归可以轻松求斐波那契数列: 一个数总是前两个数之和
0,1,1,2,3,5,8,13…… f(n)=f(n-1)+f(n-2);
方法在栈内存中执行,递归在使用的时候不能递归层数太深,不然递归过程容易导致栈溢出错误StackOverflowError。
从空间上考虑,递归比循环更耗费内存;从时间考虑,递归比循环要花费更多的时间。
递归的效率要低于循环。递归应用于某些方面易于理解。
循环——正推理,递归——反推理。
方法的修饰:
用static修饰的方法是共享的,可以直接调用方法。无static修饰的方法需要new一个类对象,通过引用对象的方式调用方法。
权限修饰符
本类中 子类中 同包类中 其他类中
public 可以 可以 可以 可以
protected 可以 可以 可以 不可以
默认 可以 同包子类可以 可以 不可以
private 可以 不可以 不可以 不可以
关于protected方法和属性
如果用protected来修饰变量与方法: 若子类a,b与父类f在同一个包,则b可以访问a的变量与方法,a也可以访问b的变量和方法。如果有一个子类c在另一个包,也c无法访问与父类在同一个包的子类a,b的变量与方法,但是与父类在一个包的子类a,b可以访问c的变量,但不能访问方法。
七、面向对象
面向对象特征:多态、继承、封装
面向对象本身是相对于面向过程而言的。
面向对象是基于面向过程。
面向过程和面向对象是思维方式。
在java里,万物皆对象!
比较分析:
①面向过程:注重每一个步骤,了解操作过程
②面向对象:注重这个对象,不了解操作过程,但获取对象就拥有对象的一切功能。
面向过程的结构化程序设计
案例:打印员工信息 ,修改员工信息后再打印
特点:执行过程是什么样的,代码就写成什么样,代码编写更偏向于计算机底层的执行思维
面向过程的结构化程序的弊端:
1.缺乏对数据的封装
2.数据和方法的分离
面向对象程序设计
更接近于人的思维方式。
将数据和方法封装为一个整体,java中将其称为类。
什么是类:类是一类事物的模板。
类的定义:成员变量(属性) 方法(行为)
一个java文件只能有一个公共类,可以有多个普通类。
成员变量:
如果一个变量声明在类的里边,方法的外边,那么这个变量就叫做成员变量。
成员变量会被程序默认初始化。
默认初始值取决于数据类型:
①int、byte、short默认值0
②long类型默认值0L
③float类型默认值0.0f
④double类型默认值0.0
⑤char类型默认值’\u0000’(表示空字符)
⑥boolean类型默认值是false
⑦引用类型,如数组、String类默认值全是null
成员变量和局部变量的区别:
1.定义位置:成员变量定义在类内,局部变量定义在方法内。
2.作用范围:成员变量作用域整个类内,局部变量作用于方法内。
3.存储位置:成员变量存储在堆内存,局部变量存在栈内存
4.成员变量会自动赋予一个默认值,局部变量不会,需赋初始值才能使用。
5.生命周期:成员变量在对象被创建的时候出现,在对象被销毁时才释放;局部变量在代码执行完之后被释放。
对象:是经由模板创建出来的具体存在的实例。
类和对象的关系:类是对象的概括,对象是类的具体展现。
调用对象中的内容,通过引用来调用。
Java将所占用的内存划分为5块:栈内存、堆内存、方法区、本地方法栈、寄存器(PC计数器)。其中静态常量池在方法区里。
对象被创建后不会自动销毁,遵循垃圾回收机制。
构造方法
构造方法名必须和类名一致。
class Student{
public Student() {} //此处如果不写,编译时会默认添加
}
(1)当在程序中使用new运算符生成对象时,系统就会自动调用类的构造方法。
(2)如果程序没有明确的定义构造方法,系统会自动为该类添加默认的无参构造方法。
注意:如果用户定义了(含参)构造器,无参数构造器就不会被自动提供,如果要使用无参数构造器,需要自己定义。
(3)构造方法也能重载。一个类可以有多个构造方法,如下例:
class Student{
String name;
int age;
char gender;

public Student() {}
public Student(String name) {}
public Student(char gender) {}
public Student(String name,char gender) {}
public Student(String name,int age,char gender) {}

}
注意:构造方法没有返回值类型。

类名命名习惯首字母大写;方法名习惯首字母小写,遵循驼峰命名法。
类名可以用public/private/abstract这三个权限修饰,也可以不写。
用static修饰的方法只能调用static修饰的属性。
构造代码块:
放在类里面,构造方法前。
在创建对象的时候,先于构造方法执行一次。

局部代码块:
定义在主方法内。
限制局部变量的作用范围,缩短局部变量的生命周期,提高栈内存利用率。

this关键字的使用方法:
①this代替当前在活动的这个对象
②this代替一个对象,用于调用属性
③this语句,可以调用本类中其他的对应形式的构造方法。
④this语句只能放在方法里的第一行

继承
对一部分的类进行分析,将这些类中共有的属性和方法提取到了一个新的类中,然后利用关键字extends让原来的类和新的类产生了关系,这种关系称为继承。
子类/派生类 extends(继承) 父类/基类/超类
子类可以用父类一部分属性和方法。
在java中,支持单继承——一个子类只能继承一个父类,但是一个父类可以有多个子类。支持多层继承——子类有一个父类,但是这个子类可以作为别的子类的父类(爸爸继承爷爷,爸爸可以被儿子继承,但是儿子不能直接继承爷爷)。
c语言支持多继承——一个子类可以有多个父类,一个父类可以有多个子类。
单继承和多继承的优劣性比较:
1.多继承代码复用性更高,优于单继承
2.单继承具有明确性,而多继承调用时容易产生歧义。
注意:子类可以继承父类所有属性和方法,前提是这些属性和方法对子类全部可见。例如用private修饰的父类属性,子类无法直接继承。

如果一个类用protected修饰其成员变量或者函数,那么这个类的子类可以拥有访问这个成员变量或者函数的权利,而其他类仍然像private的限制一样无法访问这个类的protected成员。

封装
体现形式:内部类、方法、属性的私有法——将属性用private修饰,然后提供对外的
get和set方法来获取或者设置属性,在方法中对属性进行限制是数据更加的符合场景要求。
意义:提高复用性,保证数据的合法性
优势:1.提供代码的复用性。2.保证数据的合法性。

方法的重载
方法返回值类型为对象

super关键字
表示父类对象的引用。
通过super可以在子类中调用父类的方法和属性。
如果在子类的构造函数中没有手动创建一个父类对象,那么在编译的时候会默认添加引用父类的无参构造super()。
super语句调用父类中对应形式的构造方法。
注意:
(1)如果父类是含参构造,那么super(参数) 括号里也要有对应父类的参数。
(2) super语句必须写在子类构造方法的第一行。
(3) super语句和this语句不能同时出现。
子类除了能自动继承父类的属性和方法外,还可以定义自己的属性和方法。
protected修饰的属性和方法可以在本类中、子类中、同包类中使用。
在子类中使用和子类对象使用不是一回事。
普通类里面的方法,要在main方法里通过对象调用才能输出类方法里的输出语句。
方法的重写:
在父子类中存在方法签名一致的非静态方法,称之为方法的重写/覆盖。
方法在重写的过程中需要遵守的5个原则——两等两小一大:
1.方法签名相同
2.子类重写方法的权限修饰符范围要大于等于父类
3.如果父类方法的返回值类型是引用类型,那么子类重写的方法的返回值类型和父类方法返回值类型一致或者是父类方法返回值类型的子类。
4.子类抛出的异常类型不能比父类的更宽泛,异常类型个数不能比父类方法的更多。
5.如果父类方法的返回值类型是基本类型/void,子类在重写方法是要求返回值类型一致。
@Override //用于注解当前方法是一个重写的方法。
总结:重载和重写的异同点
无论是方法的重载还是方法的重写,都是行为的多态。
重载:在同一个类中,存在方法名一致而参数列表不同的方法。方法的重载只和方法签名有关,和修饰符、返回值类型以及异常没有关系。本身是一种编译时多态。
重写:在父子类中,存在方法签名一致的非静态方法。在构成重写的时候,要求子类重写的方法的权限修饰符的范围要大于等于父类对应方法的权限修饰符的范围。如果方法的返回值类型是基本类型或者是void,那么子类在重写的时候要保持一致。如果方法的返回值类型是引用类型,那么子类在重写方法的时候返回值或者和父类对应方法的返回值类型一致,或者重写的方法的返回值类型是父类对应方法的返回值类型的子类。如果父类方法抛出了编译时异常,那么子类在重写的时候抛出的编译时异常不能超过父类异常的范围。重写本身是一种运行时多态。
多态:
编译时多态:方法的重载
运行时多态:(基于继承)
①向上造型:用父类声明了一个对象,用子类创建了这个对象。
Person p=new Doctor();
利用向上造型,调用的是重写后的方法。
在使用向上造型的时候,只会检查声明类和实现类直接是否有继承关系,而并不会检查具体哪一个是实现类。只有在运行时才会看是哪一个具体的子类,然后根据子类来开辟空间进行存储。
利用向上造型来声明的这个对象,意味着在编译期间不确定是哪个子类。
②方法的重写
运行时才知道调用的是哪个方法。
所以为了防止调用出错,所以此时不允许调用子类中单独定义的方法。
注意:在java中,基本类型之间是没有继承关系的。基本类型之间之所以能够相互转化,是因为基本类型所占的空间的大小不一致而且都是表示的数字。
Static——静态
修饰变量、方法、代码块以及内部类。
static修饰的变量为静态变量/类变量。
private static修饰的只有内部类,外部类不能用static修饰。
静态变量随着类的加载而加载到方法区,并赋初始值。静态变量先于对象出来,故静态变量不依赖于对象,可以通过类名.调用属性。例:Person.gender=”男”;
每一个对象存的是这个静态变量的地址,所以静态变量是被共享的。

java文件---->编译---->class文件---->ClassLoader(类加载器)---->(进入方法区)---->核心类库—>主方法main(String[])---->静态常量池
1.静态变量可以在方法中定义吗?——不可以——方法在调用的时候执行,到栈内存中执行。而静态变量是在类加载时初始化,存在方法区。
2.静态变量能否定义到构造函数中?——不可以——静态变量在类加载的时候初始化,构造函数在创建对象的时候执行,在栈内存中执行。
为什么静态成员、静态方法中不能用this和super关键字?
因为this代表的是调用这个函数的对象的引用,而静态方法是属于类的,不属于对象,静态方法成功加载后,对象还不一定存在 2. 在问题之前先讲super的用法:1.super的用法跟this类似,this代表对本类对象的引用,指向本类已经创建的对象;而super代表对父类对象的引用,指向父类对象;2.静态优先于对象存在;3.由上面的1.和2.知:因为静态优先于对象存在,所以方法被静态修饰之后方法先存在,而方法里面要用到super指向的父类对象,但是所需的父类引用对象晚于该方法出现,也就是super所指向的对象没有,当然就会出错。综上,静态方法中不可以出现super关键字。 3. 首先你要明白对象和类的区别。 this和super是属于对象范畴的东西,而静态方法是属于类范畴的东西所有的成员方法,都有一个默认的的参数this(即使是无参的方法),只要是成员方法,编译器就会给你加上this这个参数如:
Class A中 void method1(){} 实际上是这样的--------> void method1(A this)
void method2(int x){} 实际上是这样的--------> void method2(A this, int x)
而静态方法与对象无关,根本不能把对象的引用传到方法中,所以不能用this 4. 在一个类中定义一个方法为static,则为静态方法,那就是说,无需本类的对象即可调用此方法,调用一个静态方法就是“类名.方法名”
堆内存只用来存储对象,不能用来执行代码。
Person p=new Person(); //存储在堆内存中,地址引用是在栈内存中
static Person p=new Person(); //存储在堆内存中,地址引用是在方法区中
静态方法
在类加载的时候加载到方法区中,在方法区中不执行只是存储,在方法被调用的时候到栈内存中执行。静态方法比对象要先出来,所以可以通过类名来调用静态方法。
例Arrays.toString()
在静态方法中可以定义静态变量吗?——不可以——静态方法只有在被调用的时候才会执行,只有执行的时候才会将方法中的变量进行初始化,方法在栈内存中执行,所以方法中的变量也是存储在栈内存中。静态变量在类加载的时候初始化,静态变量存储在方法区中 。
在静态方法中可以直接调用本类中的非静态方法吗?——不可以——非静态方法在本类中是通过this,而this代表当前对象的引用。静态方法是在对象之前出现的,也就意味着静态方法执行的时候是没有对象的。
静态方法可以重载吗?——可以——方法的重载只跟方法签名有关,跟修饰符没有关系。
静态方法可以重写吗?——不可以——方法重写是指方法签名一致的非静态方法。
父子类中是否可以出现方法签名一致的静态方法——可以——但是这种形式不是重写,称为静态方法的隐藏hide。父子类存在方法签名一致,要么都是静态,要么都是非静态。
静态方法看的是声明类,非静态方法看的是实现类。
静态方法可以被继承吗?——可以

静态代码块
写在类里面,方法前,用{}括起来,前面加static修饰。
静态代码块只在类加载的时候执行一次。在栈内存中执行。无论创建多少个对象,静态代码块都只执行一次。
静态代码块在调用方法前执行。
执行顺序:加载父类---->加载子类---->创建父类对象---->创建子类对象
静态代码块—>创建类内对象—>代码块—>构造方法(若创建的对象用static修饰时排序往前一位)

Windows—>Show View—>Tasks—>可以快速查找备注TODO的代码
final
修饰数据、方法及类。
final修饰的数据称为常量,定义好后值不可变。如果是基本类型的常量,实际值不可变;如果是引用型的常量,表示地址不可变,而其中的元素或者属性可以改变。
final定义常量,在对象创建完成之前给值。
Static final 修饰成员变量成为常量,命名规范:所有字母都大写,如果由多个单词组成,单词之间用_隔开。
final修饰的变量必须初始化。初始化根据变量类型而不同:
1、static变量。只能在定义,或者静态块中初始化。
2、普通实例变量。可以在定义,非静态块,构造函数中初始化。
3、局部变量。只能在定义时初始化。
class A{
final int i;
{
i=4;
}
public A(){
}
}
如果是静态常量,需要在类加载完成之前给值。
class A{
static final int i;
static{
i=4;
}
public A(){
}
}
final修饰的方法可以被重载,可以被继承,但不能重写/隐藏。
final修饰类:最终类,不能被继承。最终类没有子类。

Final类
当关键字fina用来修饰类时,其含义是该类不能在派生子类。换句话说,任何其他类都不能继承用final修饰的类,即使该类的访问限制为public类型,也不能被继承;否则,将编译报错。
那么什么时候应该使用final修饰类呢?只有当需要确保类中的所有方法都不被重写时才应该建立最终(final)类,final关键字将为这些方法提供安全,没有任何人能够重写final类中方法,因为不能继承。
Final方法
当用final关键字修饰方法后,该方法在子类中将无法重写,只能继承。
要恰当使用final的方法,只有在子类覆盖某个方法会带来问题时,再将此方法设为final的方法,一般情况下可以不必使用
abstract
一个类中的所有子类都重写了父类的某个方法,可以把父类的这个方法声明为一个抽象方法。而抽象方法所在的类必须是抽象类。
抽象类不能用java语言实例化(创建对象)。
抽象方法一定不能用final、static、private修饰。
抽象类的权限是默认的
java底层是c语言架构的。
抽象类中不一定有抽象方法。
抽象类中可以定义抽象方法,也可以定义实体方法,可以定义属性。
意义:利用抽象类来分门别类(明确类:知道抽象类是animal,希望实现的是cat的方法。 )
抽象类必须有子类,子类方法重写所有抽象父类的方法,除非子类也是抽象类。
抽象方法与抽象(实体)方法可以重载。
抽象方法不能用static/final修饰。——static修饰的方法可以直接调用,而抽象方法不能;static修饰的方法不能被重写。
抽象方法不能用private修饰,因为private修饰的方法只能在本类中使用,对子类不可见。
如果抽象方法用的是默认权限,那么对子类有什么要求?——要求父子类必须是同包package。
抽象类中的构造方法能否私有化?——可以——但只能在类内使用。
抽象类能否用final修饰?——不可以——因为final修饰的类不能被继承。
接口
用interface定义接口,类用implements关键字实现接口。
接口里可以定义属性,系统默认用public static final修饰(可以不写),值不可变。
接口里都是抽象方法,默认用public abstract修饰,可以不写。
接口不能有构造方法,接口不是类。
可以用接口声明,实现类创建。
Animal a=new Pig(); //Animal是接口 ,Pig是实现类。
在Java中,支持单继承,多实现。——一个类只能继承一个类,可以实现多个接口。此时形成网状结构。在网状结构中购买香烟判断两个点之间是否有继承关系是一件相对复杂的事情。
为了提高编译效率,在编译期间,放弃对接口的检查。故任意一个接口强转任何一个对象时编译不报错,到运行时才会真正检查是否能够强转。
类实现接口后,必须实现接口所有方法;类中的方法都是public修饰。
多实现问题点:如果一个类实现了多个接口,并且这多个接口中存在了方法签名一致的方法就可能会导致方法的重写产生歧义。
class Pig implements Animal,Pet{} //接口名用逗号“,”隔开。
接口之间可以继承,是多继承。接口之间的继承用extends关键字。
抽象类和接口的对比

一 接口和抽象类的相似性
1 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。
2 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。
二 接口和抽象类的区别
1 接口里只能包含抽象方法,静态方法和默认方法,不能为普通方法提供方法实现,抽象类则完全可以包含普通方法。
2 接口里只能定义静态常量,不能定义普通成员变量,抽象类里则既可以定义普通成员变量,也可以定义静态常量。
3 接口不能包含构造器,抽象类可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
4 接口里不能包含初始化块,但抽象类里完全可以包含初始化块。
5 一个类最多只能有一个直接父类,包括抽象类,但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承不足。
内部类
放在类里面的类,也叫嵌套类。
内部类使用有很多限制。
方法内部类:定义在方法里的类,也叫局部内部类。
只能在定义它的方法中使用。
内部类不能定义静态变量和静态方法。可以定义静态常量static final int i=1;
方法内部类可以使用外部类的一切属性和方法。
方法内部类不能使用当前方法中的局部变量,只能使用局部常量final int i=1。
存在意义:提高代码复用性。(在一个方法里可以重复利用。)
内部类可以继承类也可以实现接口。
方法内部类只能用abstract或final修饰。
如果内部类和外部类存在方法签名一致的方法,外部类.this.方法名来调用外部类中对应的方法。
Outer.this.method();
成员内部类:
定义在类里面。
系统生成的文件默认名字:外部类 . c l a s s O u t e r 6 内部类.class 例:Outer6 Inner7.class
成员内部类可以有属性、方法 。
成员内部类不允许调用静态属性和静态方法。
成员内部类可以使用外部类的一切属性和方法,可以继承类也可以实现接口。
可以修饰类的修饰符:public、abstract、final默认。
可以修饰方法:static、final、abstract、strictfp、sysnchronized、native
可以修饰属性的修饰符:权限修饰符、static、final、volatile
在类外创建内部类对象需要使用外部类对象来创建。两种实例化方法如下:
① Outer o=new Outer();
Outer.Inner o1=o.new Inner();
② Outer.Inner o1=new Outer().new Inner();
静态内部类:
静态内部类可以定义静态属性和静态方法。
静态内部类只能使用外部类的静态属性和静态方法。

匿名内部类
只要一个类可以被继承,那么就可以存在匿名内部类。
编程中用的最多。
本质上是继承了对应的类或实现了对应的接口。
最终类不存在匿名内部类。
匿名内部类定义在方法中,那么使用规则和方法内部类一致。
匿名内部类只能使用外部用final修饰的变量(即常量)。

内部接口:类中定义的接口
类中定义的接口及接口中的定义的类和接口都是静态的。
总结:在java中,类中可以定义类,类中定义接口,接口中定义类,接口中定义接口。

猜你喜欢

转载自blog.csdn.net/weixin_42394052/article/details/85386011