面向对象编程(OOP)
1、初识面向对象
JAVA的核心思想就是OOP。
1.1、面向过程和面向对象:
面向过程思想:(线性思维)分析第一步、第二步…适合处理简单的事情。
面向对象思想:物以类聚,分类的思维,先考虑怎么分类,对每个分类进行单独思考,对分类的细节做面向过程的考虑。适合处理复杂的问题,多人协作的问题。
面向对象的本质就是:以类的方式组织代码,以对象的组织(封装)数据。
面向过程是具体的,面向对象是抽象的。三大特性:封装、继承、多态。
2、方法回顾和加深
2.1方法的定义
2.1.1&2.1.2 修饰符 & 返回类型
/*
* 修饰符 返回值类型 方法名字(...){
* 方法体
* return 返回值
* }*/
public String GOT7(){
return "I GOT 7";
}
public void IGOT7(){
return;
}
public int max(int a,int b){
return a>b? a:b;
}
2.1.3 break和return的区别
break:跳出switch,结束循环。
return:代表方法的结束,返回一个方法,返回值可以是空也可以是返回返回值类型值.
2.1.4方法名
注意规范.见名知意.
2.1.5参数列表
(参数类型,参数名)...可变长参数
2.1.6异常抛出
见下一节。
2.2方法的调用(递归)
2.2.1静态方法
static:静态方法,在另一个类中可以直接使用类名.方法名来调用。
注意:在一个类中,一个是static方法,一个不是,则static方法不可以调用非静态方法。因为static和类是一起加载的,而非静态方法是在类实例化之后才存在。
2.2.2非静态方法
无static:非静态方法,在一个类中通过实例化(创建一个对象):new 对象名().方法名()【对象类型 对象名 =new 对象值; 对象名.方法名()】来调用。
2.2.3形参和实参
形参是不存在的,实参是存在的,他们值类型必须一致。
2.2.4值传递和引用传递
JAVA是值传递:
public static void main(String[] args) {
int a=1;
System.out.println(a);
change(a);
System.out.println(a);
}
public static void change(int a){
a=10;
}
输出结果:1 1
因为并没有返回值。
引用传递:传递一个对象(一个类中只能有一个public类,但是可以有多个class)
public static void main(String[] args) {
GOT7 leader= new GOT7();
leader.name="段宜恩";
System.out.println(leader.name);
change(leader);
System.out.println(leader.name);
}
public static void change(GOT7 leader){
leader.name="林在范";
}
}
class GOT7{
String name;
}
输出结果:段宜恩 林在范
leader是一个对象,指向GOT7类
2.2.5 this关键字&&构造器
this是指向类的。例如this.name=name
;//意思是this.name就是类的成员变量=方法中定义局部变量.
类(关键字是class)和对象的关系:
类是一种抽象的数据类型,他是对某一类事物整体描述/定义,但是并不能代表某一个具体的试事物。(GOT7类)
对象是抽象概念的具体实例。(leader对象)
对象的创建:
new关键字:除了分配内存空间,还会给创建好的对象进行初始化以及对类中构造器的调用。
一个类中只有属性和方法。
public class GOT7 {
String name;
int age;
public void vocal(){
System.out.println(this.name+"林在范和崔荣宰");
}
}
public class Oop01 {
public static void main(String[] args) {
GOT7 cyj=new GOT7();
cyj.name="崔荣宰";
cyj.vocal();
}
}
类中构造器也称为构造方法,是在创建对象时必须要调用的,必须和类的名字相同,必须没有返回类型,也没有void。每个类都有一个无参构造器。
构造器作用:①使用new关键字时必须有构造器(因为new本质时调用构造器)。②用来初始化值。
public class GOT7 {
String name;
int age;
public void leader(){
System.out.println(this.name);
}
//无参构造器
public GOT7(){
this.name="林在范";
}
//有参构造器(一旦定义了有参构造,且是使用到了new,则无参构造器必须显式定义,否则new会报错:无法将类构造器应用到给定类型)
public GOT7(String name){
this.name=name;
}
}
3、对象的创建分析
1、对象使用过引用来操作的。从栈到堆(地址)。
2、属性:字段filed 成员变量
3、默认初始化:数字:0 0.0
char:u0000
boolean:false
引用:null
4、对象必须使用new关键字来创建。
4、面向对象三大特性
4.1、封装
程序要求:高内聚(类的内部数据操作细节自己完成不允许外部干涉)、低耦合(仅暴露少量的方法给外部使用)
封装:禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问。
属性私有:get/set
注意:写一个Student类,有姓名,性别等属性,如果属性是公有的,那么在别的类中可以通过new一个类对象来直接使用,即
Student Jackson=new Student();
Jackson.name="王嘉尔" ;
但是如果属性是私有(private)的,那么不可以直接对象.属性。而是要给Student类属性添加get/set方法,通过Jackson.getName()来对属性进行操作。
封装的意义:
提高程序的安全性,保护数据;
隐藏代码实现细节
统一接口
提高系统可维护性
为什么println可以输出多种类型的数据:因为方法重载.
同一个类中 两个方法 如果方法名一致,参数列表一致,那一定是同一个方法.
4.2、继承
继承的本质就是对某一批类的抽象,从而实现对现实世界更好的建模;
extends是扩展的意思,子类是父类的扩展;
Java中类只有单继承,没有多继承;(一个儿子只有一个爸爸,但是一个爸爸可以有多个儿子)
接口可以多继承。
继承是类和类之间的一种关系,除此之外,类和类之间的关系还有依赖、组合、聚合等;
继承关系的两个类,一个是子类(派生类),一个是父类(基类)。子类继承父类,使用关键字extennds来表示;子类继承父类拥有父类所有公共的方法。私有的东西是无法继承的。一般属性是私有的。
public class GOT7 {
private String name;
private int age;
public void play(){
System.out.println("GOT7 is playing");
}
}
=================================
public class Rapper extends GOT7 {
}
=================================
public class Oop02 {
public static void main(String[] args) {
Rapper rappers= new Rapper();
rappers.play();
}
}
object类
在Java中,所有的类都默认直接或者间接继承object类。
之后会更详细的学习。
super&this
this是当前类,super是(调用)父类。
this没有继承也可以使用,super必须在有继承条件才能使用。
public class GOT7 {
protected String name="JBMARKJACKSONPJRCRJBAMBAMKYG";
private int age;
public void play(){
System.out.println("GOT7 is playing");
}
}
=======================================
public class Rapper extends GOT7{
private String name="MARKJACKSONBAMBAM";
public void test(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
}
=======================================
public class Oop02 {
public static void main(String[] args) {
Rapper rappers= new Rapper();
rappers.test("GOT7的名字");
}
}
=======================================
输出结果:
GOT7的名字
MARKJACKSONBAMBAM
JBMARKJACKSONPJRCRJBAMBAMKYG
注意:
子类继承父类,在new一个子类对象时候,子类构造器会先调用父类的无参构造器,而且构造器中有“super()”这一行是存在的,执行了的但是没有显示,如果写出来,必须写在子类的构造器的第一行。
this也必须是第一个参数,所以super和this不能同时调用构造方法。
父类没有无参构造的话,子类也无法写无参构造。所以一旦创建了有参构造器,那么最好把无参构造器也写上。
super只能出现在子类的构造方法或者方法中。
方法重写
重写都是方法的重写,和属性无关。
重写需要有继承关系,只能是子类重写父类的方法,且方法名和参数列表都是一样的,方法体不同。
静态方法和非静态方法是有区别的。重写只和非静态方法有关,与静态方法无关。
父类和子类的方法都是public的,修饰符可以扩大,但是不能缩小:public>protected>default>private
(抛出的异常,范围可以缩小,但是不能被放大。ClassNotFoundException<Exception)
例如:B是A的父类:当A和B中都是静态方法时:父类的引用 指向了子类(可以通过父类new一个子类):(方法的调用值和定义的数据类型有关(即等号左边的A,B)对象能执行哪些方法主要看对象左边的类型,和右边关系不大 【两个类型A、B都有该非静态方法时,执行子类,因为重写了】) 输出结果为:A和B各自的方法。
A a=new A();
B b=new A();
当A和B都是非静态方法时,输出结果为:都是A的方法。因为A重写了B的方法。
为什么需要重写?
子类不一定需要父类方法,或者不一定能被满足。
static属于类,不属于实例,不能被重写;
final是常量,不能被重写;
private是私有的,不能被重写;
4.3、多态
多态可以实现动态编译。
即同一个方法可以根据发送对象的不同而采用多种不同的行为方式。
一个对象的实际类型是确定的,但是可以指向对象的引用类型有很多。(父类,有关系的类)
多态存在的条件:
有继承关系
子类重写父类方法
父类引用指向子类对象
注意:多态是方法的多态,属性没有多态性。
instanceof
(类型转换)引用类型,判断一个对象是什么类型。判断是否存在两个类之间是否存在父子关系。
GOT7 got7=new Rapper();
Object rappers= new Rapper();
Object vocal=new Vocal();
System.out.println(rappers instanceof Rapper);//true
System.out.println(vocal instanceof Vocal);//true
System.out.println(got7 instanceof GOT7);//true
System.out.println(got7 instanceof Object);//true
System.out.println(vocal instanceof String);//false
//System.out.println(got7 instanceof String); 编译报错 GOT7和String时同级别的。
类型转换:
基本类型转化:高转低强制
类:父类和子类之间的转化:父类时高 子类是低
//低转高 不需要强制转换
高 低
GOT7 got7=new Rapper();
//高转低 强制转换需要带括号
Rapper rapper=(Rapper)got7;
子类转换为父类,可能会丢失自己本有的一些方法。
Vocal vocal=new Vocal();
GOT7 got=vocal;
父类引用指向子类对象;
子类转换成父类,向上转型;
父类转换成子类,强制转换,会丢失方法
是为了减少重复的代码。
static小结
变量:static修饰的变量可以通过类名.属性名称来访问
方法:static修饰的方法在本类中可以使用(类名.)方法名直接被main方法访问,非静态方法需要new一个对象才能被使用。
静态方法可以调用静态方法,不能调用非静态方法。
静态代码块
{
System.out.println("匿名代码块");
}
static {
System.out.println("静态代码块");
}
public GOT7() {
System.out.println("构造器");
}
public static void main(String[] args) {
GOT7 g=new GOT7();
GOT7 got7=new GOT7();
}
}
输出结果:
静态代码块
匿名代码块
构造器
匿名代码块
构造器
匿名代码块可以用来赋初值。
静态代码块只执行一次。
静态导入包:
import static java.lang.Math.random;
package javademo;
import static java.lang.Math.random;
public class Oop02 {
public static void main(String[] args) {
System.out.println(random());
}
}
被final修饰的类不可以被继承。final之后断子绝孙
5、抽象类和接口
5.1抽象类(抽象的抽象)
abstract修饰符可以用来修饰方法,也可以用来修饰类。
public abstract class Action {
public abstract void dosth();
}
抽象类中可以没有抽象方法,但是有抽象方法的类就一定要声明为抽象类。(抽象方法必须在抽象类中)
抽象类,不能使用new关键字来创建对象,只能通过new子类来创建对象。他是用来让子类继承的。他就是一个约束。
抽象方法,只有方法的声明,没有方法的实现,(只有方法名字,没有方法体,没有{})它是用来让子类实现的。
子类继承抽象类,那么就必须要实现抽象类没有是实现的抽象方法,除非该子类也为抽象类。
抽象类不能被new,那是否存在构造器?存在,可以用来初始化一些字段。
抽象类存在的意义? 抽象共有属性,提高开发效率。
5.2接口
普通类(类关键字:class):只有具体实现。
抽象类:具体实现和规范(抽象方法)都有!
接口(接口关键字是Interface):只有规范。自己无法写方法。约束和实现分离。面向接口编程。
接口就是规范,定义的是一组规则。如果你是……,那你就会……
接口的本质是契约。规定了需要遵守。
OO的精髓,是对对象的抽象,而接口最能体现这一点。
接口中的方法都是抽象的。public abstract
接口需要有实现类。实现(implements)了接口的类就需要重写接口中的方法。
接口中那个定义的都是常量。public static final
package javademo;
public interface UserService {
int AGE=99;
void add();
void del();
}
==============================
package javademo;
public interface TimeService {
void add1();
void del1();
}
=============================
package javademo;
public class UserServiceImpl implements UserService,TimeService {
@Override
public void add() {
}
@Override
public void del() {
}
@Override
public void add1() {
}
@Override
public void del1() {
}
}
接口作用:
是一个约束,可以定义多种公共的抽象方法,可以实现多个接口,实现接口必须要重写方法。
6、内部类
内部类就是在一个类的内部定义一个类。
一个java类中可以有多个class类,但是只能有一个public class
并不推荐大量使用内部类。
6.1成员内部类
package javademo;
public class Oop02 {
private int id;
public void out(){
System.out.println("外部类");
}
class Inner{
public void in(){
System.out.println("内部类");
}
}
public static void main(String[] args) {
Oop02 out=new Oop02();
out.out();
Oop02.Inner inner= out.new Inner();
inner.in();
}
}
6.2静态内部类
package javademo;
public class Oop02 {
private int id;
public void out(){
System.out.println("外部类");
}
public static class Inner{
public void in(){
System.out.println("内部类");
}
}
public static void main(String[] args) {
Oop02 out=new Oop02();
out.out();
Inner inner=new Inner();
inner.in();
}
}
6.3局部内部类
在方法中的类
package javademo;
public class Oop02 {
private int id;
public void out(){
class Inner{
public void run() {
System.out.println("局部内部类");
}
}
}
}
6.4匿名内部类
匿名对象的使用,不用将实例保存在变量中
package javademo;
public class Oop02 {
private int id;
public static void main(String[] args) {
new A().eat();
}
}
class A{
public void eat(){
System.out.println("1");
}
}