面向对象的概念
- 面向对象是相对面向过程而言
- 面向对象和面向过程都是一种思想
- 面向过程: 强调的是功能行为
- 面向对象: 将功能封装进对象,调用具备了功能的对象。
- 面向对象是基于面向过程的 在以后的开发中其实就是找对象使用。没有对象,就创建对象。
类和对象的关系
-
现实生活中的对象:张三、李四
-
想要描述:提取对象中共性内容。对具体的抽象
-
描述时:这些对象的共性有:姓名,年龄,性别,学习的功能。
-
而描述对象时在java中就是用类的形式来体现的。而对象是java中通过new操作产生的一个实体,在推内存中存在。
类就是:对现实生活中事物的描述
对象:就是这类事物,实实在在存在的个体。
通过图来解释就如下图:
class Car{
public String color;
public String pinpai;
public void run(){
System.out.println("跑");
}
}
属性对应的是类中的变量,行为对应的是类中方法。属性和行为共同称为类中的成员(成员变量,成员方法)
生产汽车:在java中通过new操作符来完成。其实就是在堆内存上产生一个实体。
//此时c就是一个类类型变量
Car car=new Car();
现有一个需求:将已有车car的颜色改为blue。指挥该对象做使用。在java中指挥方式是:对象.对象成员
car.color="bule";
car.run();
成员变量和局部变量
- 作用范围:成员变量作用于整个类中,局部变量作用于函数或语句中。
- 在内存中的位置不同:成员变量在堆内存中,因为对象的存在,才在内存中存在;局部变量存在栈内存中。
面向对象的第一大特征:封装
封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
- 好处:
- 将变化隔离
- 便于使用
- 提高重用性
- 提高安全性
- 封装原则:
- 将不需要对外提供的内容都隐藏起来。
- 把属性都隐藏,提供公共方法对其访问。(例如set、get方法)
通过关键字private修饰类中的成员(成员变量,成员函数),使其变为私有的,私有的成员只在本类有效。将成员属性私有化后,类以外即使建立了的对象也不能直接访问,需要提供set和get方法对成员变量进行操作。
注意:私有仅仅是封装的一种表现形式。不能说封装就是将成员私有化
构造函数
- 特点:
- 函数名与类名相同
- 不用定义返回值类型
- 不可以写return语句
- 作用:
- 给对象进行初始化。
- 注意:
- 默认构造函数的特点:多个构造函数使用重载的形式存在的(方法名相同,参数不同)
观察下面代码: 对象一建立就会调用与之对应的构造函数。构造函数的作用:可以用于给对象进行初始化。
class Car{
public Car(){
System.out.println("Car run");
}
}
public class teat{
public static void main(String[] args){
Car car=new Car();
}
}
构造函数小细节: 当一个类没有定义构造函数时,系统会默认给该类添加一个无参构造函数。若在类中自定义了构造函数后,系统将不在提供默认的构造函数。当对象创建时,就会调用类中的构造方法。
下面的程序,自定义了无参构造方法,单参、两参构造方法,并在主函数中分别初始化。
class Person{
//定义两个成员变量
private String name;
private String age;
//自定义无参构造方法
public Person(){
System.out.println("无参构造方法初始化");
}
public Person(String name){
this.name=name;
System.out.println("name初始化");
}
public Person(String name,String age){
this.name=name;
this.age=age;
System.out.println("name、age初始化");
}
}
public class teat{
public static void main(String[] args){
Person person0=new Person();
Person person1=new Person("zhangsan");
Person person2=new Person("lisi","18");
}
}
构造函数和一般函数在写法上不同。在运行上也有不同:
- 构造函数是在对象一建立就运行,给对象初始化。而一般方法是对象调用才执行,是给对象添加对象具备的功能。
- 一个对象建立,构造方法只运行一次,而一般方法可以被该对象调用多次。
构造代码块
给对象进行初始化用的,对象一旦建立就执行,并且优先于构造函数执行。
classPerson{
//定义两个成员变量
private String name;
private String age;
//构造代码块
{
System.out.println("这是一个构造代码块");
}
}
构造函数和构造代码块的区别:构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化。用于定义对共性的初始化内容。
this关键字
this代表他所在函数所属对象的引用。简单地说哪个对象在调用this所在的函数,this就代表哪个对象。
//类中的构造方法
public Person(String name,String age){
this.name=name;
this.age=age;
System.out.println("name、age初始化");
}
//在主函数中new一个对象
Person person2=new Person("lisi","18");
这是表示new了一个名为person2的Person类的对象,并且调用两个参数的构造方法,因为是person2调用的所以此时构造方法中的this代表了person2,构造方法中表示将传入的值赋给person2对象在堆内存中nama属性和age属性。
this关键字的基本引用:当定义类中函数时,该函数内部要用该类对象时,这时用this来表示这个对象。
需求:给Person类定义一个比较年龄的功能,和另一个对象比较年龄。在类中添加方法:
public boolean comAge(Person person){
return this.age==person.age;
}
主函数中调用:比person1和person2的年龄
Person person1=new Person("zhangsan","19");
Person person2=new Person("lisi","18");
System.out.println(person1.comAge(person2));
this关键字在构造函数间调用(构造函数间调用只能用this语句)
//在两个参数的构造方法中调用,一个参数的构造方法,提高代码的复用性
public Person(String name){
this.name=name;
System.out.println("name初始化");
}
public Person(String name,String age){
this(name);
this.age=age;
System.out.println("name、age初始化");
}
注意事项:this语句只能定义在构造函数的第一行,否则编译失败。因为初始化动作必须先执行。
static(静态)关键字
static关键字:用于修饰成员(成员属性和成员方法)
被修饰后具备以下特点:
- 随着类的加载而加载(随着类的消失而消失。说明他的生命周期最长)
- 优先于对象存在(静态先存在。对象后存在)
- 被所有对象所共享
- 可以直接被类名调用
使用注意:
- 静态方法只能访问静态成员 (非静态方法既可以访问静态也可以访问非静态)
- 静态方法中不可以写this、super关键字 (因为静态优先于对象存在,所以静态方法中不可以出现this,super关键字 )
- 主函数是静态的
实例变量和类变量(静态变量)的区别:
- 存放位置
- 类变量(静态变量)随着类的加载而存在于方法区中。
- 实例变量随着对象的建立而存在堆内存中。
- 生命周期
- 类变量(静态变量)生命周期最长,随着类的消失而消失
- 实例变量生命周期随着对象的消失而消失
静态有利有弊:
- 利处:对对象的共享数据进行单独空间的保存,无需每一个对象都存储一个,可以直接被类名调用
- 弊端:生命周期过长。访问出现局限性(只能访问静态,不能访问动态成员)
主函数
是一个特殊的函数。作为程序的入口,可以被jvm调用
public static void main(String[] args)
主函数的定义:
- public:代表着该函数的访问权限是最大的
- static:代表主函数随着类的加载就已经存在了(静态)
- void:主函数没有具体的返回值
- main:不是关键字,但是是一个特殊的单词,可以被jvm识别
- (String[] args):函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数组
主函数也是一个函数,可以看到主函数传入了一个String类型的数组,那究竟jvm调用主函数时传递了什么参数给主函数呢?
//尝试打印里面的内容
public static void main(String[] args){
System.out.println(args);
System.out.println(args.length);
}
结果为:
可以发现jvm在调用主函数的时候,传入的是new String[0]
现在在配置中进行如下配置:
什么时候使用静态?
- 要从两方面下手,因为静态修饰的内容有成员变量和成员函数。
什么时候定义静态变量呢?
- 当对象中出现共享数据时,即所有对象中都一样,则该数据被静态所修饰,存在方法区中。
- 若是对象中的特有数据,则要定义成非静态存在于堆内存中。
什么时候定义静态函数呢?
- 当功能内部没有访问到非静态数据(对象特有数据),那么该功能可以定义成静态的。
工具类与帮助文档的制作
先自定义一个工具类,首先将无参构造方法私有化,让外部只能通过类名调用类中的静态方法。并且详细编写每个方法的文档注释。
public class util{
//将无参构造方法设为私有,让外部无法实例化对象,仅能通过类名调用类中的静态方法
/**
*空参数构造函数
*/
private util(){}
//工具类中定义获取最大值和获取最小值方法
/**
*获取整形数组中的最大值
*@paramarr接收一个int类型的数组
*@return返回数组中的做大值
*/
public static int getMax(int[]arr){
int max=0;
for(int x=1;x<arr.length;x++){
if(arr[x]>arr[max]){
max=x;
}
}
return arr[max];
}
/**
*获取整形数组中的最小值
*@paramarr接收一个int类型的数组
*@return返回数组中的做小值
*/
public static int getMin(int[] arr){
int min=0;
for(int x=1;x<arr.length;x++){
if(arr[x]>arr[min]){
min=x;
}
}
return arr[min];
}
/**
*给数组进行选择排序
*@paramarr接收受一个数组
*/
public void selectSort(int[] arr){
for(int x=0;x<arr.length-1;x++){
for(int y=x+1;y<arr.length;y++){
if(arr[x]>arr[y]){
swap(arr,x,y);
}
}
}
}
/**
*给数组进行冒泡排序
*@paramarr接收一个数组
*/
public static void bubbleSort(int[] arr){
for(int x=0;x<arr.length-1;x++){
for(int y=0;y<arr.length-x-1;y++){
swap(arr,x,y);
}
}
}
/**
*给数组中的元素进行位置的置换
*@paramarr接受一个int型的数组
*@parama需要置换的第一个参数
*@paramb需要置换的第二个参数
*/
private static void swap(int[] arr,int a,int b){
int temp=arr[a];
arr[a]=arr[b];
arr[b]=temp;
}
/**
*用于打印数组中的元素。打印形式时[a,b,c]
*@paramarr接收一个数组
*/
public static void printArray(int[]arr){
System.out.println("[");
for(intx=0;x<arr.length;x++){
if(x!=arr.length-1){
System.out.println(arr[x]+"、");
}else{
System.out.println(arr[x]+"]");
}
}
}
}
接下来,将.class文件发送给其他人,让其他人也可以使用这个工具类,只要将给文件设置到classpath路径下,就可以使用该工具类。但是该类之中到底定义了什么方法,对方并不清楚,接下来开始制作程序的说明书。java的说明书通过文档注释完成! 再命令行窗口使用javadoc命名可以自动生成说明文文档,再idea中可以通过tool下的:
静态代码块
随着类的加载而加载,只执行一次。用于给类进行初始化,并优先于主函数。静态代码块给类进行初话,构造代码块给对象进行初始化。构造函数给对应对象进行初始化的。 格式:
static
{
静态代码块中的执行语句
}
对象初始化过程:
Person person=new Person();
- 因为new用到了Person.class所以会先找到Person.class文件并加载到内存中
- 在栈内存中开辟空间用于存储引用变量person
- 静态代码块被执行
- 开辟空间用于存放成员属性,分配内存地址(new对象创建之前,首先会去方法区找是否有对应的class文件,有,然后把class文件的成员变量拿到新创建的对象中。而方法不用拿,调用时,只需取出来用即可。)
- 在堆内存中建立对象的特有属性、进行默认初始化(null)
- 显示初始化
- 构造代码块初始话
- 构造方法初始化
- 将对象地址交给占内存的person进行保存
单例设计模式
设计模式(思想):解决某一类问题最行之有效的方法。java中共有23种设计模式:
单例设计模式:决一个类在内存中只存在一个对象。
想要保证对象唯一性,应该遵循一下几点:
- 为了避免其他程序过多建立该类对象。先禁止其他程序建立该类对象。
- 为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象。
- 为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。
这三部如何用代码体现呢?
- 将构造方法私有化。
- 在类中创建一个本类对象
- 提供一个方法可以获取到该对象
演示:当需要保证对象唯一时,就可以使用单例设计模式。
class Single{
//构造方法私有化
private Single(){}
//自定义对象
private static Single single=new Single();
//返回给外部一个对象
public static Single getInstance(){
return single;
}
}
这个是先初始化对象,称为:饿汉式。Single类一进入内存就创建好了对象
单例设计模式的第二种体现:
class Single{
//构造方法私有化
private Single(){}
//自定义对象
private static Single single=null;
//返回给外部一个对象
public static Single getInstance(){
if(single==null){
return new Single();
}else{
return single;
}
}
}
这是方法被调用时才初始化没也成为对象的演示假造,称为:懒汉式。当外部需要时,才进行实例化。