Java面向对象——学习笔记(一)
文章目录
oop基础
包(package)
- 定义:在硬盘中的存在形式是目录
- 包的作用
- 让代码文件管理更直观方便
- 解决命名冲突 如:com.bailiban.StringUtil com.bailiban.StringUtil 命名不冲突
- 包的命名
- 一般使用域名的倒序来命名包名
- 不能以java开头命名,JDK已经用了
- 包的导入
-
使用其他类的时候需要导入这个包(包名+类名)
-
导包的时候在代码红线下点击导包import
-
*代表默认导入该包下所有类
-
自己的包名用package来定义,他必须写在第一行(不考虑空行跟注释)
类(class)
- 类中可以定义什么内容?
对象—抽象(特征、行为能力)—类
//属性
public String brand;
public String color;
public double price;
//行为能力
public static void call(String number) {
System.out.println("给"+number+"张三打电话");
}
public static void plagGame() {
System.out.println("她约定和我一起打王者");
}
类—孵化—对象
package com.baoliban.oop;
public class Phone {
public String brand;
public String color;
public double price;
}
package com.baoliban.oop;
public class Demo_01 {
public static void main(String[] args) {
Phone a = new Phone();
a.brand = "华为";
a.color = "red";
a.price = 8000;
System.out.println(a.brand);
System.out.println(a.color);
System.out.println(a.price);
}
}
- 传参过程详解
- 案例
(面向对象):
3.1 编写一个游戏人物类,用一个成员变量保存该人物的血量,再写一个方法用于喝药加血,每喝一次药,加5点血。
3.2 修改上题,增强喝药功能。喝药前判断当前血量是否为100,如果为100显示“您非常健康,无需嗑药”,不增加血量;若当前血量不为100,则每喝一次药,加5点血。
3.3 修改上题,增强喝药功能。调用喝药功能前,在main方法里提示用户输入喝哪种级别的药。药品级别分别有“小血瓶”、“中血瓶”和“大血瓶”。其中喝小血加5点HP,中血加15点,大血加30点。*
package com.baoliban.oop;
public class Demo_05 {
public static void main(String[] args) {
Blood b = new Blood();
Drink d = new Drink();
b.drink(d);
System.out.println("你目前的血量为:"+b.blood);
}
}
package com.baoliban.oop;
import java.util.Scanner;
public class Blood {
Scanner input = new Scanner(System.in);
int blood = 80;
public void drink(Drink d){
if(blood==100) {
System.out.println("您非常健康,不需要嗑药!");
}else if(blood<100&&blood>=0){
System.out.println("你目前的血量为:"+blood);
System.out.println("请输入你想喝的血瓶规格:大/中/小");
String a = input.next();
switch(a) {
case "大":
blood += 30;
break;
case "中":
blood += 15;
break;
case "小":
blood += 5;
break;
}
if(blood>100) {
blood = 100;
}
}
}
}
package com.baoliban.oop;
public class Drink {
}
构造器
- 定义
用于创建对象并初始化对象属性的方法,叫“构造方法”,也叫“构造器”;构造器在类中定义
- 构造方法
- 不能有返回类型,如果定义了返回类型就是成员方法而不是构造方法付
- 如果没有定义构造方法,系统会默认一个无参的构造方法
- 构造方法名必须跟类名一样
- 构造方法可以定义多个,参数列表不许不一样
public Phone(){
System.out.println("Phone对象产生1");
}
public Phone(String brand){
System.out.println("Phone对象产生2");
}
public Phone(String brand,String color,double price){
System.out.println("Phone对象产生3");
}
package com.baoliban.oop;
public class Demo_01 {
public static void main(String[] args) {
Phone a = new Phone();
Phone a1 = new Phone("华为");
Phone a2 = new Phone("华为","红色",5000);
}
}
调用方法
public Phone(String brand){
this.brand = brand;
//brand = brand; 错误示范,不能同名
System.out.println("Phone对象产生2");
}
/*a.brand = "华为";
System.out.println(a.brand);
*/
/*brand = a1;//方法内
System.out.println(a.brand);*/
- 构造器要点
构造器的名称必须与类名同名,包括大小写。
构造器没有返回值,但也不能写void,也不能写return。
构造器的参数:一般是初始化对象的前提条件。
用new调用!且对象一建立,构造器就运行且仅运行一次。一般方法可被调用多次。
类一定有构造器!这是真的,不需要质疑!
如果类没有声明(定义)任何的构造器,Java编译器会自动插入默认构造器!
默认构造是无参数,方法体是空的构造器,且默认构造器的访问权限随着所属类的访问权限变化而变化如若类被public修饰,则默认构造器也带public修饰符。
默认构造器是看不到的,一旦自己写上构造器则默认构造器就没有了,自己写的叫自定义构造器,即便自己写的是空参数的构造器,也是自定义构造器,而不是默认构造器。
如果类声明了构造器,Java编译器将不再提供默认构造器。若没手动写出无参构造器,但却调用了无参构造器,将会报错!
构造器是可以重载的,重载的目的是为了使用方便,重载规则与方法重载规则相同。
构造器是不能继承的!虽说是叫构造方法,但实际上它不是常说的一般方法。
子类继承父类,那么子类型构造器默认调用父类型的无参数构造器。
子类构造器一定要调用父类构造器,如果父类没有无参数构造器,则必须使用super(有参数的),来调用父类有参的构造器。 那么,为什么子类一定要访问父类的构造器?因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的,所以子类在对象初始化时,要先访问一下父类中的构造器。总之,子类中至少会有一个构造器会访问父类中的构造器,且子类中每一个构造函数内的第一行都有一句隐式super()。
注意事项:sper()、sper.和 this()、this.
this:在运行期间,哪个对象在调用this所在的方法,this就代表哪个对象,隐含绑定到当前“这个对象”。
super():调用父类无参构造器,一定在子类构造器第一行使用!如果没有则是默认存在super()的!这是Java默认添加的super()。
super.是访问父类对象,父类对象的引用,与this.用法一致
this():调用本类的其他构造器,按照参数调用构造器,必须在构造器中使用,必须在第一行使用,this() 与 -super() 互斥,不能同时存在
this.是访问当前对象,本类对象的引用,在能区别实例变量和局部变量时,this可省略,否则一定不能省!
如果子父类中出现非私有的同名成员变量时,子类要访问本类中的变量用this. ;子类要访问父类中的同名变量用super.
面向对象(oop)的三大特征
封装(encapsulation)
- 定义
隐藏类的内部细节,提供外部访问的接口,叫做封装,封装使用get,set方法
- 特点
- 提高安全性,提高代码复用性
- 可以隐藏内部细节,对外提供公共访问方式
-
private
(私有)只能被本类访问,不能被其他类访问 -
default
:默认属性,并且不能写出来 只要你没有用其他修饰默认就是default能被同包目录下访问 -
protected
:除了能被同包访问,还可以给不同包下的字类访问 -
public
:公共的 可以被其他包访问
package com.baoliban.oop;
public class encapsulation {
public static void main(String[] args) {
ziliao_Person z = new ziliao_Person();
z.setName("張三");
System.out.println("名字為:"+z.getName());
z.setAge(18);
System.out.println("年齡為:"+z.getAge());
}
}
package com.baoliban.oop;
public class ziliao_Person {
private String Name;
private int Age;
private String Sex;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public int getAge() {
return Age;
}
public void setAge(int age) {
if (age >= 0) {
Age = age;
} else {
Age = 0;
}
}
public String getSex() {
return Sex;
}
public void setSex(String sex) {
Sex = sex;
}
}
继承(extends)
- 定义
直接拥有父类的属性跟方法
- 注意
- java中只能拥有一个父类,单继承
- 继承后直接拥有父类的属性跟方法(不包括构造方法)
- 继承过来不满意的方法可重写
eg:
- 主类
package com.bailiban.inherit;
public class Demo_01 {
public static void main(String[] args) {
Person p = new Person();
p.setName("徐坤坤");
p.setAge(19);
p.setSex("女");
System.out.println(p.getName()+" "+p.getAge()+" "+p.getSex());
Student s = new Student();
System.out.print(p.getName()+"喜欢");
s.eat();
System.out.print(p.getName()+"喜欢的手游是");
s.play();
System.out.print(p.getName()+"的爸爸是");
s.father();
}
}
- Person类
package com.bailiban.inherit;
public class Person {
private String name;
private int age ;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public void eat() {
System.out.println("吃屎");
}
public void play() {
System.out.println("王者荣耀");
}
public void father() {
System.out.println("赵稳");
}
}
- Student类
package com.bailiban.inherit;
public class Student extends Person{
private String number;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
多态
-
定义
同一个对象的多种表现形态
父类对象引用子类实例
一个对象具备多种形态,也可以理解为事物存在的多种体现形态(父类的引用类型变量指向了子类对象,或者是接口的引用类型变量指向了接口实现类的对象)
前提:必须存在继承或者实现关系。
- 注意点
- 多态情况下,子父类存在同名的成员变量时,访问的是父类的成员变量。
- 多态情况下,子父类存在同名的非静态的成员函数时,访问的是子类的成员函数。
- 多态情况下,子父类存在同名的静态的成员函数时,访问的是父类的成员函数。
- 多态情况下,不能访问子类特有的成员。
-
总结
在多态的情况下,子父类存在同名的情况下,访问的都是父类的成员,除了在同名非静态函数是才是访问子类。
案例
- Bike类
package practice_02;
public class Bike extends Vehicle{
public String brand = "大众";
public void start() {
System.out.println("我在骑自行车!");
}
public void stop() {
System.out.println("我骑自行车累了,停下了!");
}
}
- Car类
package practice_02;
public class Car extends Vehicle{
public String color;
public void start() {
System.out.println("我的座驾是毒药!");
}
public void stop() {
System.out.println("我的毒药没油了!");
}
}
- Student类
package practice_02;
public class Student {
public void open(Vehicle v) {
v.start();
}
public void close(Vehicle v) {
v.stop();
}
}
- Test类
package practice_02;
public class Test {
public static void main(String[] args) {
Student s = new Student();
Bike b = new Bike();
Car c = new Car();
Vehicle v = new Bike();
Vehicle v1 = new Car();
s.open(b);
s.close(b);
System.out.println("---------------------");
s.open(c);
s.close(c);
System.out.println("---------------------");
v.start();
v.stop();
System.out.println("---------------------");
v1.start();
v1.stop();
System.out.println(v.num);
System.out.println(v.brand);
}
}
编译看左边,运行不一定看右边
-
调用看左边,运行看右边
父类调用子类方法。如Person p = new Student(); p.study();
-
调用看左边,运行看左边
父类调用子类属性。如Person p = new Student(); p.name;显示的是父类的name
重写与重载
重写(Override)
-
定义
把从父类继承来的不满意的方法重新写一遍覆盖
-
规则
-
返回类型:基本数据类型必须一致
引用数据类型:要么一致要么有父子关系
-
方法名:方法名必须一样
-
参数列表:必须一样
-
访问修饰符,异常
-
@Override是java用来注解下面所展示的方法为重写方法
//父类
public void eat() {
System.out.println("吃饭");
}
//子类
@Override
public void eat() {
System.out.println("吃外卖");
}
重载
-
定义
对一中功能有多重实现方式
-
规则
-
方法名一定要一样
-
参数列表一定不能一样
-
this.eat();//调用本类的方法
super.eat();//调用父类的方法this();调用子类无参构造方法
super();调用父类无参构造方法
eg:在子类中创建一个无参方法,会默认一个父类的无参构造方法super(),如果父类中没有无参构造则可以在子类中调用父类的有参构造super(“”)或者在父类中添加一个无参构造器。
eg:
//主方法
s.sleep();
s.sleep(6);
s.sleep("张三",6)
//方法类
public void sleep(){
this.eat();//调用本类的方法
super.eat();//调用父类的方法
System.out.println(睡觉);
}
public void sleep(int s){
System.out.println("睡了"+s+"小时");
}
public void sleep(String z,int s){
System.out.println(z+"睡了"+s+"小时");
}
注意:在子类中先找,找不到再去父类中找
一个类如果你没有定义它的父类,则默认继承
子父类类型强转
Person类
package practice_03;
public class Person {
public String name;
public String sex;
public int age;
public void eat() {
System.out.println("吃早饭");
}
public void sleep() {
System.out.println("睡觉");
}
}
Student类
package practice_03;
public class Student extends Person{
public void play() {
System.out.println("打游戏!");
}
public void eat() {
System.out.println("吃鱼");
}
}
SmallStudent类
package practice_03;
public class SmallStudent extends Student{
public void doing() {
System.out.println("小学生打游戏很菜");
}
}
Test类
package practice_03;
public class Test {
/**
*
* 强转 子父类类型转换
*
*
* @param zw
*/
public static void main(String[] args) {
Person a = new Student();
//多态,子父类存在同名的非静态方法时调用右边类的方法
a.eat();
//子父类不存在同名的非静态方法时调用左边边类的方法
a.sleep();
//父类强转为子类类型
Student ss = (Student) a;
ss.play();
// ((SmallStudent) a).doing(); 向线下强转错误,运行时异常ClassCastException
Student s = new SmallStudent();
((SmallStudent) s).doing();
//子类强转为父类类型
((Person) s).eat();
((Person) s).sleep();
Student s1 = new Student();
// ((SmallStudent) s1).doing(); 向线下强转错误运行时异常ClassCastException
//向线上强转
((Person) s1).eat();
((Person) s1).sleep();
((Object) s1).toString();
//Person与String没有父子关系,编译异常
// String sss = (String) a;
}
}
强转模式图
静态(static)
- 要点
-
静态的内容是属于整个类所有,被所有的对象共有
-
静态(属性方法): a,对象名.属性(方法) b,类名.属性(方法)【推荐】
-
静态的内容是在类加载的时候被初始化(.class文件生成时,在创建对象之前)
-
静态的不能调用非静态的,而非静态的可以调用非静态的。
eg:
final
- 注意
- 修饰属性表示内容不能更改,而且必须初始化
- 定义属性直接赋值
- 在构造器中初始化
- 修饰方法表示这个方法不能被重写
- 修饰类表示这个类不能被继承
Instanceof
-
定义
a instanceof b:第一个操作数表示对象,第二个操作数表示类型,表达结果是这个对象是否属于这个类型
-
补充
instanceof 也可以用来判断某个对象是否实现了某个接口
package practice_03;
public class Instanceof {
public static void main(String[] args) {
method(new Person());
method(new Student());
// method(new Object());
}
private static void method(Person p) {
//如歌判断一个对象是否是什么类型?
/*
* instanceof:第一个操作数表示对象,第二个操作数表示类型,表达结果是这个对象是否属于这个类型
* 结果输出boolean类型
*
*
* 当编译出错表示没有继承关系
* false:不满足强转条件
*
*/
System.out.println(p instanceof Student);
if(p instanceof Student) {
((Student) p).play();
}
}
}
访问修饰符
访问修饰符 | public | > | protected | > | (default)不写 | > | private |
---|---|---|---|---|---|---|---|
同一个类 | 是 | 是 | 是 | 是 | |||
同包 | 是 | 是 | 是 | 是 | |||
继承关系 | 是 | 是 | 否 | 否 | |||
没有关系 | 是 | 否 | 否 | 否 |
抽象abstract
-
定义
- 只有方法的定义,没有方法的实现,让子类去实现
- 抽象方法,被abstract关键词修饰的方法
- 抽象方法没有方法体,直接以;结束
- 抽象类不能直接实例化,使用非抽象子类
- 非抽象类不能有抽象方法
- 抽象类可以没有抽象方法(抽象类中的抽象方法个数为0—N)
-
Father
package practice_04;
public abstract class Father {
private String xin;
public Father(String xin) {
this.xin = xin;
}
public String getXin() {
return xin;
}
public abstract String family();
}
- Son
package practice_04;
public class Son extends Father{
public int age;
public String sex;
public Son(int age, String sex) {
super("赵");
this.age = age;
this.sex = sex;
}
public String family() {
System.out.println("我是father的抽象方法的实例");
return (age+sex);
}
}
- Test
package practice_04;
public class Test_abstract {
public static void main(String[] args) {
Son s = new Son(18,"男");
System.out.println(s.getXin());
System.out.println(s.family());
}
}
结果
接口(Interface) —标准和规范
-
定义
所有的方法偶不实现,找其他类来实现
-
要点
- 抽象方法的个数0-N
- 接口是不能直接实例化的,必须使用实现类(implements)
- 类可以实现多个接口,多接口(implements A,B,C)逗号隔开
- 接口是多继承
-
接口能写哪些内容?
-
常量属性:默认加上 public final static
-
抽象方法:默认加上public abstract
-
静态方法:public static void staticMehtod(){}
-
default方法:public default void defaultMethod(){}
eg:default方法是先在接口定义默认方法体,在其他类用这个方法时不满意直接覆盖
-
案例
- 工程结构图
- MyInterface
package com.bailiban.Interface;
public interface MyInterface {
String MY_NAME = "马云";
void method();
public default void defaultmethod() {
System.out.println("---接口的默认实现default---");
}
}
- ImplInterface
package com.bailiban.Interface;
public class ImplInterface implements MyInterface,Interface_A,Interface_B{
@Override
public void method() {
System.out.println("---我是接口MyInterface为实现的方法---");
}
public void defaultmethod() {
System.out.println("---接口MyInterface的默认实现default不满意,我重写定义方法体---");
}
@Override
public void method_A() {
// TODO Auto-generated method stub
}
@Override
public void method_B() {
// TODO Auto-generated method stub
}
}
- Test
package com.bailiban.Interface;
public class Test {
public static void main(String[] args) {
MyInterface m = new ImplInterface();
System.out.println(m.MY_NAME);
m.method();
m.defaultmethod();
}
}
- Interface_A
package com.bailiban.Interface;
public interface Interface_A {
void method_A();
}
- Interface_B
package com.bailiban.Interface;
public interface Interface_B {
void method_B();
}
- 运行结果
接口与抽象的区别
抽象类需要子类继承,接口需要被实现
接口里只能做方法声明,抽象类里即可以做方法的声明也可做方法的实现
接口里面的变量都是公用的静态的,抽象类里面的都是普通变量
Object(万类之祖)
toString
- 直接打印一个引用数据类型,默认调用的是这个对象的toString方法
Person p = new Person();
System.out.println(p);
System.out.println(p.toString);
equals
- ==使用在基本数据类型中比较的是指,在引用数据类型中比较的事地址
Person p = new Person();
Person p2 = new Person();
System.out.println(p == p2);
-
输出为false(因为p和p2各开辟了一个空间,地址值不同)
-
equals不能用在基本数据类型上,只能用来比较引用数据类型,比较的也是地址
Test
p.name = "王胖子";
p.age = 18;
p2.name = "王胖子";
p2.age = 20;
System.out.println(p.equals(p2));
Person
package practice_06_Object;
public class Person {
public String name;
public String sex;
public int age;
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
返回值为true,当name不一样时为false
clone
-
让类实现接口Cloneable
-
重写clone方法,扩大访问作用域
Person
public class Person implements Cloneable{
public String name ;
public String sex ;
public int age ;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}
*Test*
public class Demo02 {
public static void main(String[] args) throws CloneNotSupportedException {
Person p = new Person();
p.name = "王胖子";
p.age = 18 ;
p.sex = "男";
/*
*
* 1,让Person实现接口Cloneable
* 2,重写clone方法,扩大访问作用域
*
* 浅拷贝
*
*/
Person p2 = (Person) p.clone() ;
System.out.println(p.toString());
System.out.println(p2);
}
}