目录
一.面向对象的概念
吃饭
想吃啥---->去街上--->找馆子--->点菜---->排队等候--->吃饭
面向对象的思想特点:
1)让复杂的事情简单化
2)让我们从执行者变成了指挥者(角色发生了变化)
3)更符合我们生活中的思想行为习惯...举例:
吃饭
想吃啥--->点个外卖--->吃饭
面向对象设计的原则:
创建对象 使用对象 指挥对象做事情;
面向对象的三大特征:
封装
继承
多态
1.1类,属性,对象,方法(概念)
类: 一组事物的属性和行为的集合!
对应的真实存在事物(泛指)(举例:比如说学生,男人,女人,狗);
属性:表示事物会有什么特点(举例:狗的属性 毛色,品种,公母等等.....)
对象:描述的事物在生活中具体的,真实的一个对象.(举例: 哈士奇 母的 黑白毛色)
方法:表示这个事物可以有什么功能,能干嘛?(举例:哈士奇 拆家,看家 ,吃,睡)
代码实现举例
需求:学生有姓名,年龄,性别属性,行为有学习,睡觉以及玩游戏的行为.
请使用面向对象方式书写学生类并且进行测试.
class Demo{
public static void main(String[] args){
//创建一个学生类的对象;
Student student = new Student();
//给对象初始化属性
student.name = "刘海柱";
student.age = 19;
student.sex = "男";
//d打印输出这个真实的对象
System.out.println(student.name+"\t"+student.age+"\t"+student.sex);
//.调用他的方法
student.learn(student.name);
student.sleep(student.name);
student.playGame(student.name);
}
}
//创建一个学生类
class Student{
成员变量
String name;//名字
int age ;//年纪
String sex;//性别
//学习(方法)
public void learn(String name){
System.out.println(name+"会学习.");
}
//睡觉
public void sleep(String name){
System.out.println(name+"会睡觉.");
}
//打游戏
public void playGame(String name){
System.out.println(name+"会打游戏.");
}
}
1.2局部变量和成员变量有什么区别(概念)
1.代码书写的位置不同
局部变量:定义在方法中或者是方法声明上
成员变量:定义在类中,方法之外
2.内存中的位置不同
局部变量:在栈内存中
成员变量:在堆内存中
3.生命周期不同
局部变量:随着方法的调用而存在,随着方法调用的结束而消失
成员变量:随着类的加载而存在,类加载完毕之后,等待垃圾回收器自动回收,不会很快释放
4.初始化不同
局部变量:定义的时候必须初始化,或者在使用之前必须初始化,否则会报错
成员变量:系统会给默认初始化(null/0),也可以自己初始化,不过无意义
1.3引用类型作为参数传递(类)
基本类型作为形式参数传递,形式参数的改变不会影响实际参数!
引用类型在作为参数传递,形式参数的改变会直接影响实际参数!(除了String字符串之外)
数组,类,接口
类:
具体类:实际参数传递需要的是该类的对象!(空间地址值)
class Test{
public static void main(String[] args){
Student s = new Student();
StudentDemo sd = new StudentDemo();
//实际参数传递需要的是该类的对象!(空间地址值)
sd.method(s);
}
}
//定义一个学生类
class Student{
public void learn(){
System.out.println("勤奋刻苦的学习中......");
}
}
//定义一个学生Demo类
class StudentDemo{
public void method(String n){
//设置一个形式参数,传入值后访问learn方法并且输出语句
n.learn();
}
}
1.4匿名对象:
匿名对象:
没有名字的对象!
格式:
new 类名() ;
特点:
1)开发中使用一次即可
2)使用完毕,立即被回收,可以结束内存空间!
这种写法针对:移动端: Android(考虑内存问题)
3)作为参数传递
pc端:推荐:
类名 对象名 = new 类名() ;
class Student{
//成员方法
public void study(){
System.out.println("爱生活,爱Java...") ;
}
}
class StudentDemo{
public void method(Student s){
s.study() ;
}
}
//测试类中
class NoNameDemo{
public static void main(String[] args){
//需求:访问StudentDemo类中method
//分步骤:
//创建StudentDemo类的对象
StudentDemo sd = new StudentDemo() ;
//创建一个具体的学生类对象
Student student = new Student() ;
sd.method(student) ;
System.out.println("-----------------------") ;
//链式编程
//匿名对象(只限于自己玩,开发中正常使用有名字的对象)
new StudentDemo().method(new Student()) ;
}
}
二.面向对象的三大特征
封装
概念:将一个事物的属性,特征,私有化.(对外进行隐藏) ,只能在本类中访问,外部不能直接访问(保证了数据的安全性),需要访问时需要提供对外访问的公共类方法来间接调用访问成员变量.
private关键字: 私有的,外界不能访问,只能在本类中访问(权限修饰符);
特点:被private修饰过的成员变量和成员方法,都只能在本类中访问,如需外部访问,需要通过公共方法间接访问;
this关键字:代表了当前类对象的地址值的引用;
代码举例说明private和this关键字:
需求:定义学生类
姓名,和年龄两个属性,属性私有化,提供公共访问方法赋值/获取值学习,玩游戏.
class Student{
//封装(私有化成员变量)让外部不能直接访问
private String name;//姓名
private int age;//年龄
//因为采用了私有的封装,这里需要定义两个方法setXXX和getXXX来间接调用成员变量,给赋值和访问
public void setName(String name){
//这里的this代表了当前类的对象的地址值,表示把传入进来的name值给这个类地址下的name,完成赋值
this.name = name;
}
public void setAge(int age){
this.age = age;
}
//访问方法
public String getName(){
//因为已经用set赋值给了当前类中的name,所以调用的时候只需返回name即可
return name;
}
public int getAge(){
return age;
}
//成员方法
public void study(){
System.out.println("学习java....");//学习的方法
}
public void playGame(){
System.out.println("玩游戏.....");//玩游戏的方法
}
}
//测试Student类
class TestStudent{
public static void main(String[] args){
//创建一个学生对象
Student student = new Student();
student.setName("老王");//用创建的这个学生类访问setName(方法)传入实参
student.setAge(34);
//输出传入的值(用当前创建的学生类访问getXXX直接会返回对应的值)
System.out.println("姓名:"+student.getName()+",年龄:"+student.getAge());
//调用成员方法
student.study();//输出 学习java....
student.playGame();//输出 玩游戏.....
}
}
2.1.1构造方法
构造方法时一个特殊的方法,需要在类中自己构造
方法名和类名一致
没有具体返回值类型
没有void
格式:
权限修饰符(public:目前使用居多) + 类名(xx){}
构造方法是可以重载的;
构造方法作用:
就是为了 给类中的成员变量进行数据的初始化!(构造方法初始化!)
构造方法的分类:
1.无参构造方法
如果在定义类的时候没有构造方法,系统默认无参构造方法.
举例:public Student(){} 这个就是一个无参构造方法,也可以不写,系统会自动默认
注意:如果我们提供一个有参构造方法,系统不会在提供无参构造方法!(建议永远在给除有参构造方法的同时给出无参构造方法)
2.有参构造方法
在定义的类中自己构建,目的就是为了给类中的成员变量传入参数进行初始化
public Student(String name , int age){
this.name = name;
this.age = age;
}
一个标准类的组成
1.成员变量
2.加入构造方法(有参/无参)
3.成员方法
代码举例(改造上面学生类代码)
需求:定义学生类
姓名,和年龄两个属性,属性私有化,提供公共访问方法赋值/获取值学习,玩游戏.
用有参类和无参类分别构造和输出
class Student{
//封装(私有化成员变量)让外部不能直接访问
private String name;//姓名
private int age;//年龄
//无参构造
public Student(){}
//有参构造
public Student(String name , int age){
this.name = name;
this.age = age;
}
//因为采用了私有的封装,这里需要定义两个方法setXXX和getXXX来间接调用成员变量,给赋值和访问
public void setName(String name){
//这里的this代表了当前类的对象的地址值,表示把传入进来的name值给这个类地址下的name,完成赋值
this.name = name;
}
public void setAge(int age){
this.age = age;
}
//访问方法
public String getName(){
//因为已经用set赋值给了当前类中的name,所以调用的时候只需返回name即可
return name;
}
public int getAge(){
return age;
}
//成员方法
public void study(){
System.out.println("学习java....");//学习的方法
}
public void playGame(){
System.out.println("玩游戏.....");//玩游戏的方法
}
}
//测试Student类
class TestStudent{
public static void main(String[] args){
方法1:
//创建一个学生对象
Student student = new Student();
student.setName("老王");//用创建的这个学生类访问setName(方法)传入实参
student.setAge(34);
//输出传入的值(用当前创建的学生类访问getXXX直接会返回对应的值)
System.out.println("姓名:"+student.getName()+",年龄:"+student.getAge());
//调用成员方法
student.study();//输出 学习java....
student.playGame();//输出 玩游戏.....
方法2:
//有参创建一个学生对象
Student student1 = new Student("老李",23);
//输出传入的值(用当前创建的学生类1访问getXXX直接会返回对应的值)
System.out.println("姓名:"+student1.getName()+",年龄:"+student1.getAge());
//调用成员方法
student1.study();//输出 学习java....
student1.playGame();//输出 玩游戏.....
}
}
2.1.2 static关键字
java提供了一个static关键字,意思是静态的,随着类的加载而加载,并且跟类一样,只加载一次.而且被static修饰过的属性可以被多个对象"共享".
代码举例:
本代码采用方法重载,减少代码的冗余.
先构造一个有参(String int String)三个参数的方法,将p1的这个对象的实参传入到里面去,因为四个美女的国籍都是中国,所以在第一次赋值完之后country就是中国
后期几个人只需要在类中调用这个已经初始化过后的属性就可以.
//定义一个类:人类
class Person{//Preson.class
private String name ; //姓名
private int age ; //年龄
static String country ;//国籍
//有参构造方法
public Person(String name,int age ,String country){
this.name = name ;
this.age = age ;
this.country = country ;
}
//带两个参数的构造方法
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
public void show(){
System.out.println("这个人姓名是-"+name+",年龄是-"+age+",所在的国籍是-"+country) ;
}
}
//测试类
class PersonTest{
public static void main(String[] args){
//古代四大美女
Person p1 = new Person("西施",18,"中国") ;
p1.show() ;
System.out.println("------------------------") ;
Person p2 = new Person("貂蝉",25) ;
p2.show() ;
System.out.println("------------------------") ;
Person p3 = new Person("杨玉环",28) ;
p3.show() ;
System.out.println("------------------------") ;
Person p4 = new Person("王昭君",23) ;
p4.show() ;
System.out.println("------------------------") ;
}
}
static关键字的特点
1.static随着类的加载而加载
2.优先于对象的存在
3.不能和this公用
4.被static修饰过的成员变量/方法(静态变量/静态方法),有"共享、公用"的意思
5.被静态修饰的变量或者方法,可以直接调类名.方法名/变量名使用
注意事项:
非静态的成员方法可以访问静态和非静态的方法(包括非静态成员变量和静态成员变量)
静态的成员方法只能访问静态的方法和成员变量(这些方法和变量都是和类相关的)
代码举例:
//Demo类
class Demo{//Demo.class
//静态
public static int number = 100 ;
//非静态
public int number2 = 20 ;
//非静态的成员方法
public void show(){
System.out.println(number2) ;
System.out.println(number) ;
System.out.println("-------------------") ;
function() ;//静态方法
method() ;
}
public void method(){
System.out.println("method demo") ;
}
//静态方法
public static void function(){
//System.out.println(number2) ; //无法从静态上下文中引用非静态 变量 number2
System.out.println(number) ;
System.out.println("function demo") ;
//method() ;//无法从静态上下文中引用非静态 方法 method()
}
}
2.1.3代码块
在java中,使用{}包裹起来的代码,称为代码块
代码块的分类:
1.静态代码块:在类中方法外的static{ // 代码块 }
随着类的加载而加载,类加载一次,静态代码块就执行一次.
2.构造代码块:
写在类中方法外的代码块在执行构造方法之前先执行,对数据进行初始化!
特点:每次执行构造方法之前,如果存在构造代码块,优先执行构造代码块,在执行构造方法!
3.局部代码块
方法中定义,用于限定局部变量的声明周期
执行优先级:静态代码块 > 构造代码块 > 局部代码块;
看程序写结果:
class Student{
static{
System.out.println("student的静态代码块1") ;
}
{
System.out.println("student的构造代码块1") ;
}
public Student(){
System.out.println("Student类的无参构造方法") ;
}
static{
System.out.println("student的静态代码块2") ;
}
public Student(String name){
System.out.println("Student类的有参构造方法") ;
}
{
System.out.println("student的构造代码块2") ;
}
}
class StudentTest{
static{
System.out.println("在测试构造代码块...") ;
}
public static void main(String[] args){
System.out.println("我是main方法...") ;
Student s = new Student() ;
System.out.println("-----------") ;
Student s2 = new Student("代码块") ;
}
}
-------------------------------------------------------------------
输出:
在测试构造代码块...
我是main方法...
student的静态代码块1
student的静态代码块2
student的构造代码块1
student的构造代码块2
Student类的无参构造方法
-----------
student的构造代码块1
student的构造代码块2
Student类的有参构造方法
继承
开发过程中,可能会遇到很多类,但他们如果有同样的共性,我们可以把共性抽取出来放到一个独立的类中,让这个独立类和其他类产生一种关系:继承
格式
class 子类 extends 父类{
//子类独有的特征
}
继承的特点:
1)类与类之间的继承关系,不支持多继承,只支持单继承.
2)类与类之间的继承关系可以多层继承.
继承的好处:
1)提高了代码的复用性
2)提高了的代码的维护性
3)让类与类之间产生关系 ----- 是 "多态的前提条件"
继承代码示例
//父类
class Animal{
private String name;//姓名
private int age;//年龄
private String color;//颜色
//构造无参方法
public Animal(){}
//使用公共方法进行赋值
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public void setColor(String color){
this.color = color;
}
//访问
public String getName(){
return name;
}
public int getAge(){
return age;
}
public String getColor(){
return color;
}
}
class Cat extends Animal{
}
class Dog extends Animal{
}
//测试类
class AnimalTest{
public static void main(String[] args){
Cat cat = new Cat();
cat.setName("小白");
cat.setAge(3);
cat.setColor("白色");
System.out.println("姓名:"+cat.getName()+",年龄:"+cat.getAge()+",颜色:"+cat.getColor());
Dog dog = new Dog();
dog.setName("小黑");
dog.setAge(5);
dog.setColor("黑色");
System.out.println("姓名:"+dog.getName()+",年龄:"+dog.getAge()+",颜色:"+dog.getColor());
}
}
继承中成员变量的访问:
子类继承符类:如果成员变量名称不一致的情况下,分别输出即可.
子类继承父类:如果子类的成员变量名称和父类成员变量名称一致的情况下
a)现在本类的局部位置找,有没有这个变量,如果有就直接使用
b)如果本类的局部位置没有,在本类的成员位置中找,如果有,就使用
c)如果本类的成员位置没有,在它的父类的成员位置找,如果有,就使用
d)父类的成员位置都没有这个变量,压根不存在,就报错!
继承中构造方法的访问:
在继承过程中,只能继承父类的成员变量和成员方法,不能继承父类的构造方法.
可以使用super();间接访问父类的成员方法,以达到初始化的目的.
子类的所有构造方法都默认访问父类的无参构造方法:子类每一个构造方法第一句隐藏super();
继承中存在默认访问的问题,在写父类的时候一定要给出父类的无参构造.
为什么默认访问的是父类的无参而不是父类的有参?
子类在初始化的时候,可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用(子类在初始化之前,一定要先完成父类的初始化)
class Zi{
public Zi(){
super();//默认给出,如果不写的话
System.out.println("这是子类的无参构造方法");
}
}
2.2.1super和this的区别
this:代表的本类对象的地址值引用
super:代表的父类空间标识(父类对象的地址值引用)
this.变量:访问的本类的成员变量
this.方法名():访问的本类的成员方法
this()/this(xx):访问本类的无参构造方法/访问的本类的有参构造方法
super.变量名:访问的是父类的成员变量
super.方法名():访问的父类的成员方法
super()/super(xx):访问的父类的无参构造方法/访问的父类的有参构造方法
2.2.2方法重载和方法重写的区别
方法重载overLoad
定义方法的时候,如果多个方法的方法名相同,参数列表不同,与返回值无关
参数列表不同:顺序不同,类型不同,个数不同
方法重写overRide
子类继承父类,出现了和父类一模一样的方法声明(权限,返回值,方法名,参数列表都相同),方法覆盖
为了将父类的功能覆盖掉,使用自己的功能!
注意:子类继承父类,要重写父类的功能的时候,必须要保证子类的方法的访问权限足够大,要么
就父类的权限保持一致即可!
2.2.3final关键字
final最终的,无法更改的
可以修饰类,该类不能被继承
可以修饰变量:修饰完过后变量是一个常量:自定义常量
可以修饰方法:此时这个方法不能被重写
多态
一个事物在不同状态下的不同状态
如何理解多态:
简单来说,多态就是一种事物在不同状态下的体现.比如说我定义一个动物类,动物类那么动物都有吃的功能,但是食草动物在吃的时候,和
食肉动物在吃的时候他吃的东西是不一样的.到底是吃肉还是吃草,多态就是把吃什么,在具体对象中具体体现出来。
使用多态的前提条件:
1.必须要产生继承的关系
2.必须有方法重写(子类继承父类,需要将父类的功能覆盖掉) 使用子类的功能;
3.必须存在父类引用指向子类对象("向上转型")
Fu fu = new Zi();
多态中成员访问的特点:
成员变量:编译看左,运行看左
成员方法:编译看左,运行看右
多态的弊端:
不能访问子类的特有功能!
向上转型:父类引用指向子类对象
如果能够使用子类型,就可以访问它的功能!解决方案: 向下转型(强转) 前提是必须有向上转型的前提
Zi zi = (Zi)fu;(这样做的好处是不用再栈内存中重新开辟内存空间)
多态的向下转型,如果使用不当,会出现异常!
ClassCastException:类转换异常:
堆内存中的变化 和接收的类型不匹配!
示例:
//父类
class Animal2{
}
//子类
class Cat2 extends Animal2{
}
class Dog2 extends Animal2{}
//测试类
public class DuoTaiDemo4 {
public static void main(String[] args) {
//多态创建对象
Animal2 a = new Cat2() ; //堆内存中猫的实例 (猫是动物)
Cat2 c = (Cat2)a ; //将猫还原了 (猫是猫) 向下转型
a = new Dog2() ;//堆内存中是狗的实例(狗是动物)
Dog2 d = (Dog2)a; //还原成狗了
// Cat2 c2 = (Cat2)a; //ClassCastException:类转换异常:属于运行时期异常!
}
}
多态的好处:
1)可以提高代码的复用性 (是由继承保证的)
2)可以提高代码的扩展性(多态完成:父类引用指向子类对象:Fu f = new Zi()) ;
3.1.1抽象类(abstract关键字)
在现实世界存在真实事物,本身就是概括性的事物,这个时候,为了将具体的事物的功能给出具体体现,那么当前概括性的事物中
加入抽象-----abstract,并且它里面的一些功能仅仅只是声明,并不给出具体体现!
在具体对象创建的时候,我们才值到他具体的行为方法.例如:动物有吃的方法,但是我们不知道他吃什么,如果创建一个猫的对象
那我们就知道猫能吃鱼.
public abstract class XXX{
}
一个类中有抽象方法,这个类一定是抽象类.
抽象类中不一定有抽象方法
抽象方法
就是没有具体方法体的方法
public abstract 返回值类型 方法名(形式参数);
3.1.2接口
接口是什么?
接口是一个比抽象类还抽象的类,只有常量(默认public static final 数据类型 XXX)和成员的抽象方法组成(默认是abstract 修饰欸有具体代码块)
用来实现对象的额外功能,体现了一种扩展性,也是java中弥补了类与类不能多继承的缺陷。
接口的成员特点
成员变量:只能是常量,存在默认的修饰符 public static final
构造方法:无
成员方法:只能是抽象方法,存在默认修饰符:public abstract
3.1.3抽象类和接口的区别
1.成员的区别
成员变量:
抽象类可以可以是常量(使用final)也可以是变量。
接口必须是常量(存在默认修饰符 public static final)
构造方法
抽象类有构造方法,有参和无参。针对父类进行分层初始化
接口没有构造方法。
成员方法
抽象类可以是抽象方法(抽象类中不一定有抽象方法,有抽象方法的肯定是抽象类,abstract修饰)
接口只能是抽象方法,存在默认修饰符 public abstract
2.关系的区别
3.1.4类与类,类与接口,接口和接口之间的关系
类与类之间只能是单继承,不能多继承,但可以多层继承 extends
类与接口之间是实现的关系,一个类继承另一个类的同时,可以实现多个接口,中间用,隔开。implements
public Zi extends Fu implements 接口1 , 接口2 , .... { }
接口与接口之间是继承关系,可以单继承也可以多继承
interface 接口名1 extends 父接口1,父接口2,...{}
3.设计理念的区别
抽象类 体现的继承关系(类与类之间的关系居多),---描述 "is a"的关系
接口 实现关系:一个事物所具备的额外功能,---描述的是一种"like a"的关系
3.1.5形式参数为引用类型传递(接口和抽象类)
抽象类:需要传递的是当前抽象类的子类对象(抽象类多态,抽象类不能实例化,需要通过子类去实例化)
接口:需要传递的是当前接口的子类实现类对象(接口无构造方法,需要通过接口多态去实现)
权限修饰符
默认修饰符 | private | portected | public | |
同一个类中 | √ | √ | √ | √ |
同一个包的子类/其他类 | √ | √ | √ | |
不同包的子类 | √ | √ | ||
不同包其他类 | √ |
package包的概念
1.包名全部小写
2.包的命名方法:域名倒置法
3.cn.com.XXX(每一个点就是一个下级目录)
4.package xxx.xxx写在代码的首行
5.带包编译和带包运行
javac -d . Xxxx.java
java xxx.xxx.Xxxx(class文件名)
返回值问题研究
方法的返回值如果是抽象类的情况
return 当前抽象类的子类对象
返回值类型是接口类型
return 该接口的子实现类对象