java之面向对象
Java 是面向对象的高级编程语言,类和对象是 Java 程序的构成核心.
面向对象的三大特征:封装,继承,多态
面向对象与面向过程的区别
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
总的来说:面向对象时基于面向过程的思想,面向过程强调的是每一个功能的步骤,而面向对象强调的是对象有对象去调用功能
面向对象的思想特点:
- 是一种跟符合我们思考习惯的思想
- 可以将复杂的事情简单化
- 将我们从执行者变成了指挥者
类与对象的概述:
Java语言最基本的单位是类;
类可以看做是事物相关属性和行为的集合,而对象就是该事物的具体体现。
其实面向对象和现实世界是紧密相关的,我们可以通过面向对象对现实世界进行描述,我们可以把一个事物看做是一个对象,我们可以把事物的特征和描述看做是属性,把这个事物有什么行为能够做什么看做是一个一个的功能,比如说猫,这个猫是一个类,它有一个名字叫做小柒,小柒就是这个类中具体的对象,小柒是只公猫,我们可以把猫的性别看做这个对象的属性,猫能吃鱼,我们可以把这个行为看做是猫的一共功能;
代码如下:
package demo;
/**
* `猫的描述和行为
* 描述:
* 猫的名字
* 猫的性别
* 猫的年龄
* 行为:
* 猫吃鱼
* 猫抓老鼠
* `将猫看成是一个类:
* 猫的描述就是这个类的成员变量(属性):
* 猫有一个名字的成员变量(属性):name
* 猫有一个性别的成员变量(属性):sex
* 猫有一个年龄的成员变量(属性):age
* 猫的行为可以看做是类的一个方法(功能):
* 猫吃鱼对应类中吃鱼的方法:eatFish()
* 猫抓老鼠对应类中老鼠的方法:grabMouse()
*
* @author ange
*
*/
public class Cat {
/**姓名*/
public String name;
/**性别*/
public String sex;
/**年龄*/
public int age;
/**
* 猫吃鱼
*/
public static void eatFish() {
System.out.println("猫吃鱼");
}
/**
* 猫抓老鼠
*/
public void grabMouse() {
System.out.println("猫抓老鼠");
}
}
成员变量:和变量是一样的只是位置不同成员遍历是在类中方法外.
成员方法:就是方法写在类中没有static关键字
类的使用:
使用一个类其实就是使用类的方法和成员变量
1.创建对象:我们想要使用一个类就必须拥有该类的对象
使用new关键字创建对象
语法格式:
类名 对象名 = new 类名();
package demo;
public class CatDemo {
public static void main(String[] args) {
//创建一个Cat对象
Cat cat = new Cat();
System.out.println(cat);
}
}
控制台打印结果:demo.Cat@15db9742
demo.Cat@15db9742这个是一个地址值,因为new出来的东西会在堆中创建一个内存空间,然后通过这个地址值指向内存空间,这个之后详细介绍;
类成员的使用(成员变量,和成员方法的使用):
访问成员变量:对象名.方法名([参数…]);//中括号中[]代表可选如果有参数方法则需要传参数,没有则不传.
访问成员方法:对象名.变量名;
代码演示:
package demo;
public class CatDemo {
public static void main(String[] args) {
//创建一个Cat对象
Cat cat = new Cat();
// System.out.println(cat);
//使用成员变量
System.out.println("猫的名字"+cat.name);
System.out.println("猫的性别"+cat.sex);
System.out.println("猫的年龄"+cat.age);
}
}
控制台打应:
猫的名字null
猫的性别null
猫的年龄0
为什么会出现null和0,因为没有给成员变赋值,成员变量是有默认值的,name(名字)和sex(性别)是String类型,Stirng类型是引用数据类型,引用数据类型默认值为null,age(年龄)是基本数据类型,基本数据类型的默认值为0;
给成员变量赋值:
语法格式:
对象名.成员变量名=值;
package demo;
public class CatDemo {
public static void main(String[] args) {
//创建一个Cat对象
Cat cat = new Cat();
// System.out.println(cat);
//使用成员变量
System.out.println("未赋值");
System.out.println("猫的名字"+cat.name);
System.out.println("猫的性别"+cat.sex);
System.out.println("猫的年龄"+cat.age);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
//给成员变量赋值 对象名.成员变量名=值;
cat.name="小柒";
cat.age=1;
cat.sex="男";
System.out.println("已赋值");
System.out.println("猫的名字"+cat.name);
System.out.println("猫的性别"+cat.sex);
System.out.println("猫的年龄"+cat.age);
}
}
控制台打应结果:
未赋值
猫的名字null
猫的性别null
猫的年龄0
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
已赋值
猫的名字小柒
猫的性别男
猫的年龄1
调用成员方法:
语法格式:
对象名.方法名([参数]);
package demo;
public class CatDemo {
public static void main(String[] args) {
//创建一个Cat对象
Cat cat = new Cat();
// System.out.println(cat);
//使用成员变量
System.out.println("未赋值");
System.out.println("猫的名字"+cat.name);
System.out.println("猫的性别"+cat.sex);
System.out.println("猫的年龄"+cat.age);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
//给成员变量赋值
cat.name="小柒";
cat.age=1;
cat.sex="男";
System.out.println("已赋值");
System.out.println("猫的名字"+cat.name);
System.out.println("猫的性别"+cat.sex);
System.out.println("猫的年龄"+cat.age);
System.out.println(">>>>>>>>>>>>>>>>>>>>");
//调用成员方法
System.out.println("成员方法");
cat.eatFish();
cat.grabMouse();
}
}
控制台打印结果:
未赋值
猫的名字null
猫的性别null
猫的年龄0
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
已赋值
猫的名字小柒
猫的性别男
猫的年龄1
>>>>>>>>>>>>>>>>>>>>
成员方法
猫吃鱼
猫抓老鼠
对象内存图
每new一个对象都会在堆内存中创建一个内存空间
[外链图片转存失败(img-VdaC5JNa-1563561153647)(C:\Users\Administrator\Desktop\内存.png)]
两个引用指向同一对象内存图
面向对象三大特征之封装
成员变量与局部变量的区别
A:在类中的位置不同
成员变量:类中,方法外
局部变量:方法中或者方法声明上(形式参数)
B:在内存中的位置不同
成员变量:堆内存
局部变量:栈内存
C:生命周期不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
D:初始化值的问题
成员变量:有默认值
局部变量:没有默认值。必须先定义,赋值,最后使用
面向对象封装:
1.封装:
含义:指隐藏类的属性成员变量,仅对外提供公共访问方式;
作用:提高了代码的复用性,提高安全性;
1. private关键字:(私有化属性)
特点:被其修饰的属性或方法,只能在本类中被访问使用;
应用:可用于封装和私有方法;
权限修饰范围:
权限范围:public > protected > 默认 > private
public: 项目级
protected: 不同包子类(可以在同一个包,也可以不同包)
默认: 同包
private: 类级
2. this关键字:[就近原则]
特点:代表当前对象的引用(谁来调用我, 我就代表谁!)
应用:1.解决局部变量隐藏成员变量的问题! 例如:this.name = name;
2.当成参数传递,代表调用者;
公共访问方式:快捷键:(alt + shift + s) 自动生成get,set;或构造方法,重写
1.set(设置)
例如:
public void setName(String name) {//设置名字
this.name = name;
}
2.get(获取)
例如:
public String getName() { //获取名字
return name;
}
3. 赋值输出
1.成员变量赋值
1.setXxx()方法;(一直给一个对象赋值)
2.有参构造方法;(赋值会创建对象)
2.输出成员变量值
1.getXxx()方法;
2.show()方法;(本类普通方法)
3.构造方法(Constructor):
作用:1.给对象的属性进行初始化;开辟内存空间,创建对象–>new;
1. 构造方法组成:
只有访问修饰符和类名,再加参数,return可写可不写;
2. 种类:无参,有参(重载:方法名相同,参数列表不同);
1.空参构造:
public Student () {
}
Student stu1 = new Student(); //创建无参对象;
System.out.println(stu1.name); //打印成员变量;
2.有参构造:
public Student (String name,int age) {
this.name = name;
this.age = age;
}
Student stu2 = new Student(“张三”,12); //创建有参对象,并赋值;
System.out.println(stu2.name); //打印成员变量;
3. 构造方法特点
1.创建该类的对象时,调用该类相应的构造方法;
2.如果在一个类中,没有给出任何构造方法,jvm会自动提供一个无参构造方法;
3.如果我们给出了构造方法,系统将不再提供默认的无参构造方法。(建议自己给出无参构造方法)
4.static关键字:
作用:被static修饰的是类变量或静态方法,没被修饰的是普通的变量和方法;(native)
调用格式:类名.属性; 类名.方法名();
1. 存放位置:
静态区:存放被static修饰的变量和方法,随类的加载而加载,可以立即使用;
非静态区:存放不被static修饰的变量和方法,随类的加载而加载,不能被直接使用,只用创建了对象才能被使用;
2. 静态和非静态
1. 静态变量和成员变量的区别
类变量: (被static修饰的成员变量)
1.是类变量,以字节码文件形式存储在方法区的静态区中;
2.随着类的加载而加载(只会加载一次),随着类的消失而消失;
普通成员变量: (属于对象,所以也称为实例变量)
1.是实例变量,存储于堆内存中对象里面;
2.随着对象的创建而存在,随着对象的消失而消失;
2. 静态和非静态调用规则:
静态:
1.静态访问静态,直接类名打点调用;
2.静态访问非静态,只能通过对象名打点调用;
非静态:
1.非静态访问静态,直接类名打点调用;
2.非静态访问非静态,只能通过对象名打点调用;
总结:只要被调用者是静态的,都可以用:类名.方法名();直接调用;
在一个类内部,直接方法名或属性调用,因为JVM会在前面默认加类名;
3. static特点:
1.随着类的加载而加载;
2.优先于对象存在;
3.对类的所有对象共享(被接下来的对象所共享);
4.static不能在非静态方法中使用;不能修饰局部变量;
5.在静态方法中不能使用this和super关键字;不能直接调用类的非静态属性;
4.项目里面类的来源:(电脑保存的就只有文件和文件夹的形式;)
1. 来源于我们的自定义类:
1.使用者与被使用的类,如果路径一致,可以不导包,直接使用类;
2.使用者与被使用的类,如果路径不一致,必须要导包!==> import语句导包!
2. 来自java的核心类库(Scanner Math String …ArrayList):
1.这个类如果是属于java.lang包,不需要导包,可以直接使用;//例:String System
2.这个类不是属于java.lang包,使用之前,必须要导包;//例:Scanner
3. 来源外部导入:
导入jar包的形式 ==> 解决[本项目]想要使用[别的项目]里面的类
4. 工具类:(ArrayTool)
含义:专门用来实现一些固定的功能的类, 这种类就是[工具类];
1.工具类中, 所有的方法必须全部用static静态修饰 //目的: 为了调用更方便! 例: Math.Random()
2.私有构造方法,这个类构造方法要被private修饰;
面向对象三大特征之继承
*含义:让类与类之间产生关系, 子父类关系;
*继承的好处和弊端:
A:继承的好处
1.提高了代码的复用性(只要是非私有属性和行为 父类里面写一遍, 所有的子类都具有这个属性值!)
2.提高了代码的维护性
3.让类与类之间产生了继承关系, 继承关系是 [多态] 的前提!
B:继承的弊端
1.类的内聚性减弱了;内聚:就是自己完成某件事情的能力(尽量自己独立完成,不依赖别的类)
2.类的耦合性增强了;耦合:类与类的关系;
开发的原则:高内聚,低耦合。
1.继承形式
1. Java里面的类只支持单继承,不支持多继承;(一个直接的父类)
class Dog extends Animal { //一个类只能继承一个类
}
2. Java支持多层继承,不支持循环继承;(多个间接父类)
class 爷爷类 { //间接父类
int age = 12;
}
class 父类 extends 爷爷类 {//直接父类
int a = 12;
}
class 子类 extends 父类 {
String color; //只有子类里面才有!
}
2.继承特点
1.子类只能继承父类所有非私有的属性和方法;
2.子类不能继承父类的构造方法,但是可以在自类构造方法内用super()访问;
2.私有属性可以通过公共访问方式set()和get()访问;
3.如果没有直接父类,默认直接父类是Object类,任何类,都直接或间接的继承Object类;
4.要所有功能,就用最底层的类创建对象;要共性功能,就用最顶层的类创建对象;
3.继承属性和方法的调用
1. 调用规则:
[就近原则]:局部位置–>本类的成员位置–>父类的成员位置
this:代表本类对象的引用; 例如:this();无参 this(color);有参
super:代表当前对象父类的引用; 例如:super(); super(color);
1.成员变量:
直接:syso(num);
本类:syso(this.num);
父类:syso(super.num);
2.成员方法:
直接:fuMethod();
本类:this.fuMethod();
父类:super.fuMethod();
3.构造方法:
直接:默认为父类
本类:this();或this(color);
父类:super();或super(color);
4.this和super的用法:(this和super,在类内部或子类调用)
1.构造方法默认第一条语句是:super();手动给this,系统就不再给默认的super()语句;
2.子类对象默认先访问父类的空参构造方法;用super手动调用,才访问父类有参构造方法;
3.this和super在一个方法内,必须要是方法的第一条语句,而且不能共存;
4.本类的空参和有参不能同时相互调用;
2. 代码内存执行步骤:(子类创建对象)
1.先对父类的属性初始化;
2.执行父类的构造方法;(无参,有参)
3.对子类的属性进行初始化;
3.执行子类的构造方法;(无参,有参)
4.方法重写
1.重写和重载的区别
重载:本类重载本类方法,方法名相同,参数列表不同;
重写:子类重写父类方法,方法名相同,参数列表相同,访问修饰符权限更大,抛出异常类型比父类大;
2.重写作用:当父类的方法不能完全满足子类使用的时候,就需要重写父类的方法;
3.重写规则:重写对方法签名不做修改(或修改修饰符),只对方法体进行修改;
注解:@Override 提示重写方法错误;(放在方法前面)
//方法签名: public void Pet()
//方法的实现(方法体):{方法体语句}
注意事项:
1.父类中私有方法不能被重写;
2.父类静态方法,子类也必须通过静态方法进行覆盖;
5.final关键字修饰类
查看源码:
软件的位数:32位,64位;
32位:x86 2^32 64位:是32位的2^32倍
final修饰特点
1.修饰类:类不能被继承;
2.修饰方法:方法不能被重写;
3.修饰属性:表示这个属性不可修改,且声明该final属性时,必须赋值;
4.常量定义:public static final 数据类型 常量名 = 值;
5.修饰变量:表示该变量的值不能改变,可以在声明的时候不赋值,也可以声明后再赋值;
final关键字修饰局部变量
基本类型,只能被赋值一次!
引用类型,对象的地址值不能被改变,对象中的属性可以改变
面向对象三大特征之多态
1.多态
*含义:一个引用类型(类类型),给实例不一样,执行操作不一样;
例如:new 的子类对象赋值给父类的类型;
Pet p = new Dog(); p.eat(); 调用dog的eat();
Pet p = new Cat(); p.eat(); 调用Cog的eat();
1. 多态实现的要素:
1.必须有继承;
2.必须有重写,如果没有重写,就体现不出变化;
3.父类类型来接收子类对象;
2.多态的作用:
1.解决重复代码,代码的重用;
2.程序的可扩展性提高;(代码的升级)
3. 多态的体现方式:
1.父类类型作为方法的参数,接收子类的对象;
public void feed(Pet p) {//类名作为方法参数;
p.eat(); //Pet p = new Dog();
}
Lady L = new Lady(“Joney”);
L.feed(d); //向上转换:自动转换为父类(重写方法可以直接访问)
2.父类类型作为方法的返回值类型;
public Pet getPet(int num) {//类名作为方法返回值;
switch(num) {
case 1:
System.out.println(“领养小狗成功!”);
return new Dog(“小黄”,60,60);
}
Pet p = girl.getPet(num);
if(p instanceof Dog) {
Dog d = (Dog) p;//向下转换:父类强制转换成子类;
girl.feed(d);
d.showof();
}
4. 多态中向上转型和向下转型
编译看左边,运行看右边;
1.向上转型:实现多态的必要条件;
把子类自动转换为父类,子类特有的属性和方法不能访问;
Pet p = new Dog();
2.向下转型:需要调用子类特有的方法和属性;(必须先有向上,才有向下)
把父类强制转换为子类,需要自己写 (子类)父类对象;
Dog d = (Pet) p;
instanceof(异常处理):判断对象是否是类的一个对象,或者是类的子类对象;
向下转换:会出现如下的异常Exception: ClassCastException
(对象 instanceof 类名):boolean类型
Ture:对象是类的一个对象,或者类的子类的对象;
False:否则不是;
2.抽象类
抽象类:abstract修饰的类;
抽象方法:abstract修饰的方法;(没有具体的方法体的方法,只有方法签名)
1. 格式:
abstract class Animal { //抽象类;
public abstract void eat();//抽象方法:
}
2. 抽象类特点:
1.抽象类只能被继承,不能被实例化,构造方法只是供子类调用属性;
2.抽象类中可以没有抽象方法,但抽象方法必须位于抽象类中;
3.一个类继承了抽象类,要么重写所有抽象方法,要么自己也是抽象类;
4.abstract不能和final和private关键字共存;
3.接口
含义:interface修饰的类;
接口作用:
1.实现多继承;
2.标准化,使用接口对项目的方法进行标准化,统一方法的签名;
1. 格式:
interface 接口名 {}
抽象方法 //没有非抽象方法,没有属性;
常量 //没有构造方法,不能被实例化;
例如:
public interface UsbInterace {
int A = 10;
void service();
}
2. 接口的特征:
1.接口是一个特殊的抽象类,里面全都是抽象方法;
2.成员变量默认都是public static final类型;
3.没有构造方法,不能被实例化;
4.抽象方法默认都是public abstract类型;
3. 接口继承:extends
1.继承接口,必须重写接口的所有抽象方法;
2.接口可以继承多个接口;(普通类只能继承一个类)
4. 接口实现:implements修饰
1.一个接口不能实现另一个接口,只能继承接口;
2.实现类实现某个接口,必须重写接口中所有的抽象方法;
3.接口也可称为实现类的父类,同样具备继承时多态的功能,但作为父类类型时,只能调用接口定义的方法;
4.一个类可以实现多个无关紧要的接口(实现多继承), 例如:implements 接口1,接口2,…
4.异常
编程的错误:语法错误,编译过程中不通过;
异常(Exception):程序正常编译,只是在运行过程中出现的问题,可能出现,可能不出现;
1. 异常产生的原因:
1.用户的不正当操作;
2.程序员不小心造成的;
2. 处理方式:
1.用户不正当操作:提示用户正常操作;
2.程序员引起的异常:修改,调BUG;
例如:计数器:计数器的相除;
3. Java对异常的结构体系图:(异常也是一个类)
Think in java java编程思想;
编译时异常:写代码一定需要捕获,如果不捕获,编译不通过;
运行时异常:写代码,可以捕获,可以不捕获;
4. 异常的处理:
1.try catch [finally](捕获异常,提示异常的情况)
try{//可能出现异常的代码
代码1
代码2(可能出现的异常)
}catch(异常类型 e){
//处理catch小括号中异常
System.out.println("")
}catch() {
}
finally {//可写可不写,表示不管前面代码是否出现异常,最终都要执行 //关闭资源,BT下载,电驴;//比如IO资源,jdbc资源;
}
1.情况分析:
第一种情况:try没有产生异常,程序正常执行,不会执行catch中的代码;
第二种情况:try产生异常,异常是catch的异常类型,执行catch代码,并继续执行catch后面代码
第三种情况:try产生异常,异常不是是catch的异常类型,异常后面的代码不会执行,
中断程序的运行,并且会把异常的信息抛到控制台。
2.注意:
1.如果try后面接的多个catch,先子类异常,再写父异常类型;
2.try不能单独存在,后面必须要跟catch或finally;
3.try中定义的变量只能在try中使用;
4.try中不管出现什么类型的异常,后面在try内语句都不执行,但都会执行finally语句;
5.有return返回值,也会执行后面的finally语句;
2.throws throw(声明异常并抛出异常)
作用:把异常抛出,给调用者;
throws:写在方法的参数列表后面,声明该方法可能会抛出什么类型的异常,可以有多个,也可没有;
如果抛出的是编译时异常,必须要声明;
throw:写在方法内部,抛出定义的异常对象,throw返回的是一个异常对象,类似于return;
例如:
public void fun1() throws IOException,RuntimeException{//申明可能抛出的异常
int i = 1;
if (i == 1) {
throw new IOException();
}
else if (i == 1) {
throw new RuntimeException();//抛出的异常
}
}
注意:异常可以一层一层往上抛,最后到Java虚拟机;
3.拓展内容:
e.printStackTrace(); //打印异常的堆栈信息;
String msg = e.getMessage();//获取简洁信息;
System.out.println(msg);
4.注意事项:
1.
3.分析异常:调BUG
1.一测就死
2.半死不活
3.结果与预想不一样,逻辑有问题;
异常处理步骤:
先异常的类型-->再找异常的简介信息-->找自己类的第一行,跳转到问题代码区;
4.日志记录
1.业务日志记录;
2.异常信息的记录:出现异常记录,原因,解决方案,解决问题经验;
3.SQL(数据库)语句记录,SQL优化,