目录
面向对象的基本概念
面向对象的编程思想
面向对象是一种编程设计思想,在面向过程的编程设计思想中(例如c语言),是面向步骤进行编程的,该思想的编程是对实际问题一步一步利用方法进行解决,例如做一顿饭需要使用洗菜(),烧水(),炒菜()等方法。
而在面向对象的思想中,会先用分类的思想对整体事物进行分析,对事物之间的整体关系进行分类,再对类进入深入的描述,面向对象的思想更符合人类的认知习惯。
面向对象与面向过程的关系:
在程序设计的过程中,面向对象是无法替代面向过程的,两者相辅相成。编程设计过程中,宏观上使用面向对象的方式把握事物之间的关系,而在微观的细节实现上仍然采用面向过程的思想解决问题看。
Java类
类是一种模板,是一类事物的属性与行为的集合,是对客观世界的某一类事物的基本特征的抽象。
例如汽车根据汽车设计图来进行生产
图中的汽车设计图就是类,是汽车生产的模板
类的结构
1.成员变量:事物属性的描述;
2.成员方法:事物的行为;(可以做的事情)
3.构造方法:初始化对象;
4.内部类: 即在类体中声明的类。
5. 块:一段没有名称的代码块
类的定义
第一步 发现类
例如各种类型与品牌的汽车都可以归属与一个汽车类
类的声明格式为: [访问权限修饰符] [修饰符] class Car{……}
public class Car {……}
类的命名规范:首字母大写,要见名知意,用大驼峰表示
第二步 发现类的共有属性
例如汽车共有的属性有,名称,价格,颜色等
声明成员变量(属性)的格式为: [访问权限修饰符] [修饰符] 数据类型 变量名 ;
//成员变量的声明
String name;
int price;
String color;
第三步 发现类的共有行为
例如汽车中共有的行为有,行驶,停止等
方法声明格式为: [访问权限修饰符] [修饰符]/ void start(){ 方法体; [return 返回值;] }
//定义类中共有的方法
public void run(){
System.out.println(name+"正在行驶");
}
public void stop(){
System.out.println(name+"停下来了");
}
public void destory(){
System.out.println(name+"撞毁了");
}
Java对象
在现实世界中万事万物都是对象
可以认为对象是以类为模板创建的一个具体的实例,实际上是一个类型的变量,内存会单独为其分配一个存储空间。
类在定义完之后是无法直接用类名来调用类中的成员变量与成员方法的,类在最终使用的时候还是需要根据类来实例化一个具体的对象,用对象来完成具体的功能。
上图中类为汽车设计图,而对象为被生产出来的汽车。
对象的创建
声明语法格式:
类名 对象名=new 类名();
对象创建之后就可以使用的对象名来访问对象中的成员变量与成员方法
同一个类中的不同对象有不同的存储空间
同一个类的不同对象共享类的成员方法
//创建一个汽车的对象
Car lslshy=new Car();//new Car();实际上是一个构造方法可以返回存储对象的地址
lslshy.name="劳斯莱斯幻影";
lslshy.price=10000000;
lslshy.color="玫瑰金";
lslshy.run();
lslshy.stop();
lslshy.destory();
//一个类可以实例化多个对象
Car fll=new Car();
fll.name="法拉利";
fll.price=1000000;
fll.color="红色";
fll.run();
fll.stop();
fll.destory();
对象与类的关系
类是一个模板、模型,是一个抽象的概念,而对象是根据类来创建的一个具体的实例,所以对象的创建也叫类的实例化
在现实世界中,是先有对象才分出来的类
而在程序设计的过程中是先设计类再创建的对象
变量的分类
在前面学过java的变量由数据类型可以分为基本数据类型和引用数据类型,基础类型包括基本的八个类型引用类型已经接触的包括String,数组,类与接口
而如果按照变量所处的位置来分的话,变量可以分为成员变量与局部变量
成员变量
成员变量写在类中,其类型可以是java所支持的所有数据类型
成员变量在类中定义的时候,可以不对其进行初始化,在创建对象的时候java会为其初始化默认值
成员变量在创建对象时会从类中复制一份到对象的中
成员变量可以被方法,构造方法,特定的语句块调用,其作用范围在整个类中
成员变量的生命周期为,对象的创建开始到对象的销毁结束
局部变量
局部变量写在方法或者代码块中,数据类型可以是java所支持的所有数据类型
局部变量与成员变量不同的是局部变量在使用前必须进行初始化,否则无法调用
局部变量的作用范围就是方法内或者代码块内
局部变量的生命周期为方法调用入栈开始到方法调用出栈结束
方法的分类
方法可以分为构造方法与成员方法
成员方法
成员方法写在类中,完成类的某种行为(功能)
成员方法声明格式为:
[访问权限修饰符] [修饰符]/ void start(){ 方法体; [return 返回值;] }
/*
发现类的共有行为
即成员方法
*/
public void run(){
/*
局部变量 只方法内生效且需要初始化
*/
int a=0;
System.out.println(name+"正在行驶"+a);
}
构造方法
概念:用来初始化新创建的对象的方法
构造方法名与类名相同,且没有返回值,且不需要使用void修饰。
作用:
1.在构造方法中为创建的对象初始化赋值, 在创建一个对象的时候,至少要调用一个构造方法。
2.每个类都有构造方法。如果没有显式地为类定义构造方法,Java将会为该类提供一个默认 构造方法,但是只要在一个Java类中定义了一个构造方法后,默认的无参构造方法即失效。
3.一个类可以有多个构造方法。
/*
构造方法
创建对象时初始化对象的方法
类中会有一个默认的构造方法,可以为对象的属性赋默认值
*/
public Car(){
System.out.println("调用一个无参的构造方法");
}
/*
一个类中可以有多个构造方法,可以使用相同的方法名,这是构造方法的特点,也是方法的重载
此处定义了一个有参的构造方法
若是类中定义了一个有参的构造方法,则原来默认的无参构造方法消失,若想调用则需要定义一个显示的无参构造方法
*/
public Car(String name,int price,String color){
this.name=name;
this.price=price;
this.color=color;
}
方法的重载
通过构造方法的特点中,一个类中可以创建多个构造方法可以引出方法的重载的概念
方法的重载即一个类中有多个方法名相同的现象称为方法的重载
区分不同重载的方法:
由于方法名称是相同的,故在调用时都是使用同个名称进行调用的,java中是通过参数的类型,个数,顺序来区分不同的方法的,但是通过返回值的类型无法区分重载的方法。
/*
构造方法
*/
public Car(){
System.out.println("调用一个无参的构造方法");
}
/*
构造方法的重载
*/
public Car(String name,int price,String color){
this.name=name;
this.price=price;
this.color=color;
}
/*
成员方法
*/
public void run(){
int a=0;//局部变量 只方法内生效且需要初始化
System.out.println(name+"正在行驶"+a);
}
/*
成员方法的重载
*/
public void run(int speed){
System.out.println(name+"正在行驶"+"速度是"+speed);
}
对象与引用
对象与对象引用的创建实际上就是上面学习的对象的创建过程,但是在其中可以细分三个步骤
1.创建对象: new Car(),以Car类为模板在堆空间中创建一个Car类对象
2.声明对象引用:Car car;创建一个Car类型的引用变量,该类型的变量变量创建后可以让其用来指向Car对象
3.赋值:将创建对象的地址赋值给对象引用
举例子说明
new Car(); 这个语句在堆空间里创建了实体,尽管它们也是确确实实存在的实体,但是, 我们看不见,也摸不着这个实体。 对象没有名字,也就没法直接访问它。我们需要通过对象引用来间接访问对象。 对象好比是一只很大的气球,但是我们抓不住它。引用变量是一根绳,可以用来系汽球。 Car car1; (1)创建一根绳子,一根还没有系上任何一个汽球的绳; Car car2;(2)就又做了一根绳,还没系上汽球, car1 = new Car();(3)给car1 系上气球; car2 = car1 ;(4)这里,发生了复制行为。要说明的是,对象本身并没有被复制,被复 制的只是对象引用。 结果是,car2也指向了car1所指向的对象。两根绳系的是同一只汽球。
//创建对象与声明对象引用1
Car car1=new Car();
car1.name="宝马";
car1.price=500000;
//创建对象与声明对象引用2
Car car2=new Car();
car2.name="大众";
car2.price=100000;
Car car3=car2;//对象引用car2复制给了对象引用cae3,两者引用用一个对象
car3.name="奔驰";//此时改变是对car2与car3共同引用的对象中的成员变量
System.out.println(car2.name);
对象,类在内存中的存储位置
参数传递
java中的参数传递可以分为值传递与引用传递,但是在本质上都是对数值进行的传递
值传递:针对的基本数据类型,变量和值都是一起存储在栈中的
引用地址传递:针对的引用数据类型,每次传递的是对象引用也就是对象的地址,而不是传递对象本身,其中对象引用存储在栈中,而对象存储在堆中
//值传递的案例
public static void main(String[] args) {
int a=10;
new Demo1().test(a);//创建Demo1类的一个变量然后调用该变量的方法
System.out.println(a);//结果为10,基本类型的变量和值都存储在栈中,另外一个方法的基本变量间除非人为操作不然那不会互相影响
}
public void test(int b){
b=20;
}
//引用地址传递的案例
public class Demo2 {
public static void main(String[] args) {
Car car1=new Car();
car1.name="宝马";
new Demo2().test(car1);
System.out.println(car1.name);//输出结果为奔驰,这是由于对象存储在堆空间中,
// 调用test方法只是将对象引用car1复制给了car,即将对象的地址赋值给了car,并不是传递对象
}
public void test(Car car){
car.name="奔驰";
}
}
this关键字
this关键字代表当前的对象,当形参与成员变量名称相同时,可以用this关键字调用成员变量的方式区分两者
例如this.成员变量
public Car(String name,int price,String color){
this.name=name;//this表示当前正在调用的对象
this.price=price;
this.color=color;
}
static关键字
static被称为静态,可以用来修饰类的属性、方法、代码块、内部类
一般所有对象都共享的数据且不变的数据用static来修饰
static修饰的成员方法变量存储在内存的方法区中,在内存中只存储一份
静态修饰的变量与方法建议直接使用类名访问,但是对象也可以访问静态变量与静态方法
public class Chinese {
String name;
String adress;
int age;
/*
static修饰符
static修饰的变量只有一份,故不会和对象一起存储在堆内存中,而是会和类一起存在方法区中
*/
static String country="中国";//static修饰的静态变量被所有对象共享
}
//类的调用
public class ChineseTest {
public static void main(String[] args) {
Chinese zs=new Chinese();
zs.name="张三";
zs.age=18;
zs.adress="汉中";
zs.showInfo();
Chinese ls=new Chinese();
ls.name="李四";
ls.age=20;
ls.adress="西安";
//可以用对象调用静态变量
System.out.println(zs.country);//输出中国
//也可以用对象访问静态变量
ls.country="china";
System.out.println(zs.country);//输出china
System.out.println(ls.country);//输出china,此时静态变量被修改,所有对象访问的静态变量都改变
System.out.println(Chinese.country);//建议直接用类名对静态变量进行访问
}
}
static的特点
随着类的加载而加载(比成员变量与成员方法先加载)
优于对象先存在,先加载类再加载对象
修饰的成员被所有对象共享
可以不创建对象,直接使用类调用
static修饰方法
static可以修饰成员方法,所修饰的成员方法不能调用成员变量,而只能调用静态的成员变量,由于是静态的方法故可以直接使用类名调用,静态方法存储在内存中的方法区中,且可以不用创建对象就可以直接调用静态方法,在一定程度上可以节省空间,非静态的方法可以访问静态的变量
public class Chinese {
String name;
String adress;
int age;
/*
static修饰符
static修饰的变量只有一份,故不会和对象一起存储在堆内存中,而是会和类一起存在方法区中
*/
static String country="中国";//static修饰的静态变量被所有对象共享
}
//类的调用
public class ChineseTest {
public static void main(String[] args) {
Chinese zs=new Chinese();
zs.name="张三";
zs.age=18;
zs.adress="汉中";
zs.showInfo();
Chinese ls=new Chinese();
ls.name="李四";
ls.age=20;
ls.adress="西安";
//可以用对象调用静态变量
System.out.println(zs.country);//输出中国
//也可以用对象访问静态变量
ls.country="china";
System.out.println(zs.country);//输出china
System.out.println(ls.country);//输出china,此时静态变量被修改,所有对象访问的静态变量都改变
System.out.println(Chinese.country);//建议直接用类名对静态变量进行访问
}
}
代码块
代码块在类中声明,是一段没有名称的代码,类似一个没有名称的方法体
代码块分为实例块和静态块
实例块
在每次对象创建时都会自动执行 实例块既可以调用成员变量也可以调用静态变量
/*
代码块
*/
int a;
static int b;
/*
实例块
在每次对象创建时都会自动执行
实例块既可以调用成员变量也可以调用静态变量
*/
{
System.out.println("实例代码块1"+a);
}
{
System.out.println("实例代码块2"+b);
}
静态块
随着类的加载自动执行一遍,且只有一遍 静态代码块只能调用静态变量
/*
静态块
随着类的加载自动执行一遍,且只有一遍
静态代码块只能调用静态变量
*/
static{
System.out.println("静态代码块1");
}
static{
System.out.println("静态代码块2"+b);
}
//两段代码的测试代码
public class TestDemo {
public static void main(String[] args) {
System.out.println(Demo.b);//加载类调用静态块,调用的顺序是在类加载之后,即在调用之前会加载类
Demo demo1=new Demo();//创建对象调用实例块
Demo demo2=new Demo();
}
}
/*输出结果
静态代码块1
静态代码块20
0
实例代码块10
实例代码块20
实例代码块10
实例代码块20
*/
小总结
1.触发类加载的条件:
调用类名,静态变量,静态方法或者创建对象
2.类加载时各元素的加载顺序:
先加载静态的成员,按照定义顺序从上到下
成员变量
实例块
构造方法
成员方法
3.若是在一个文件中定义两个类那么在编译的过程中就会出现两个class类的文件
包
概念:包是用来管理类的机制,用于为类作命名空间(相当于类的地址)
全类名=包名+类名
Improt关键字:导入其他包中的类 但是Java.lang类不需要导入就可以调用
包的作用:
1.避免类名重复:若是在一个类中需要使用两个包中的同名类,此时其中一个类必须写全类名才能识别两个不同的类
2. 按照不同的功能管理类: 例:公共的功能、数据库的功能、前端交互的功能
3. 控制访问的权限等
包名的命名规范
全部小写,并且用.号来区分包的级别
第一级:指项目的类别 例:com. org. gov. 等
第二级:指项目开发的公司或者单位 例:huawei. sun. 等
第三级:项目名
第四级:功能模块名
第五级……
package com.yzl.javaOOP.packagedemo;//包名的命名规范
/*
import关键字导入其他包中的类
java.lang中的类不需要导入可以直接使用
*/
import day1.Car;
import java.util.Date;
public class PackageDemo {
public static void main(String[] args) {
/*
包:用来管理类的机制,用于为类作为命名的空间
全类名:包名+类名
*/
Car car=new Car();//创建其他包中的类就需要导入包
Date date1=new Date();
Date date2=new java.sql.Date(20);//java不会自动识别不同包中的重名类,若需要导入不同包中的重名类则需要使用全类名
//全类名=包名+类名
String s="";//String属于java.lang类,该类不需要导入就可以直接使用
}
}
访问权限控制符
可以修饰类、属性、方法
public :公共权限 修饰类、属性、方法 任意类访问
protected:受保护的权限 修饰属性、方法。 只能被同包类访问与该类的子类可以访问。
default:同包权限 修饰类、属性、方法 只能被同包的类访问
private:私有权限 修饰属性、方法 只能在本类中访问
public class Demo1 {
/*
访问权限修饰符
*/
public int pubnum;//公共属性
protected int pronum;//受保护的属性
int num;//默认的属性
private int prinum;//私有属性
//本类中的属性在本类中都可以被访问
public void pubtest(){
System.out.println("公共方法");//公有方法
System.out.println(pubnum);
System.out.println(pronum);
System.out.println(num);
System.out.println(prinum);
}
protected void protest(){
System.out.println("受保护的方法");//受保护的方法
}
void test(){
System.out.println("默认的方法");//默认的方法
}
private void pritest(){
System.out.println("私有的方法");//私有的方法
}
}
//测试类
public class Demo2 {
public static void main(String[] args) {
Demo1 demo1=new Demo1();
System.out.println(demo1.pubnum);//同包的类访问public修饰的属性
System.out.println(demo1.pronum);//同包的类访问protected修饰的属性
System.out.println(demo1.num);//同包的类访问default修饰的属性
//同包中的类不能访问private修饰的变量与方法
demo1.pubtest();//同包的类访问public修饰的方法
demo1.protest();//同包的类访问protected修饰的方法
demo1.test();//同包的类访问default修饰的方法
}
}
//测试类另外一个包中的类
package com.yzl.javaOOP.packagedemo;
import com.yzl.javaOOP.day1.Demo1;
public class Demo3 extends Demo1 {
public static void main(String[] args) {
Demo1 demo1=new Demo1();
System.out.println(demo1.pubnum);//不同包中的类只能访问public修饰的变量
demo1.pubtest();//不同包中的类只能访问public修饰的方法
Demo3 demo3=new Demo3();
System.out.println(demo3.pronum);//不同包中的子类可以访问受保护的属性
demo3.protest();//不同包中的子类可以访问受保护的方法
}
}