------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
面向对象
一、理解面向对象:在Java中,高手们的概念就是万物皆对象。
(1) 面向对象的概念:
面向对象:是基于面向过程的一种思想。
面向过程:强调的是功能行为。
面向对象:将功能封装进对象,强调具备了功能的对象。
面向对象是基于面向过程的。
(2) 面向对象和面向过程:
(3) 面向对象特点:
面向对象就是一种常见的思想。符合人们的思考习惯。
面向对象的出现,将复杂的问题简单化。
面向对象的出现,让曾经在过程中的执行者,变成了对象中的指挥者。
(4) 面向对象有三个特征:封装,继承,多态
以后的开发过程:其实就是找对象用。没有对象,就创建一个对象。
找对象,建立对象,使用对象,并维护对象的关系。
二、 类和对象
类和对象的关系:
类:就是对现实生活中事物的描述。
对象:就是这类事物,实实在在存在的个体。
想要描述:提取对象中共性内容。对具体的抽象。
映射到Java中描述就是class定义的类。
具体对象就是对应Java在堆内存中用new建立实体。
例子:
需求:描述小汽车。描述事物其实就是在描述事情的属性和行为。
分析: <1>,属性:轮胎数。颜色。 <2>,行为: 运行。
定义类其实就是在定义类中的成员。成员:成员变量<-->属性,成员函数<-->行为。
属性对应是类中变量,行为对应的类中函数或方法。
其实定义类,就是在描述事物,就是在定义属性和方法,属性和行为共同成为类中的成员(成员变量和
成员方法)。 类中不必有主函数,不必保证独立运行,只有保证有一个主函数入口调用类就行。
//描述汽车类
class Car
{
//描述汽车的颜色
String color ="red";
//描述汽车的轮胎数
int num=4;
//描述车的运行
void run()
{
System.out.println("color="+color+"..."+"num="+num);
}
}
class CarTest
{
public static void main(String[] args)
{
//生成汽车,在Java中通过new操作符来完成
//其实就是在堆内存产生一个实体
Car c = new Car();//为什么要加括号呢?
//c就是一个类类型变量记住:类类型变量指向对象
//需求:将已有车的颜色改成蓝色,指挥该对象做使用,在Java中指挥方式是:对象.对象成员
c.color = "bule";
c.run();//color=bule...num=4
new Car().color="green";//匿名对象,不过调用匿名对象的属性没有意义。
new Car().run();//匿名对象调用方法,只调用一次。打印的结果是color=red...num=4
method(new Car()); //可以将匿名对象作为实际参数进行传递
}
//需求:汽车修配厂,对汽车进行改装,将来的车都改成黑色,三个轮胎。
public static void method(Car c)
{
//将汽车的颜色喷漆成黑色
c.color="black";
//将汽车的轮胎改成3个
c.num = 3;
c.run():
}
}
匿名对象:没有名字的对象 。
new Car();//匿名对象。其实就是对象的简写格式。
(1) 当对象对方法仅进行一次调用的时候,就可以简化成匿名对象。
(2) 匿名对象可以作为实际参数进行传递。
注意:调用匿名对象的属性是没有意义。
成员变量和局部变量的区别:
(3) 成员变量定义在类中,作用于整个类中。
局部变量定义在函数,语句,局部代码块中,只在所属的大括号区域有效。
(4) 成员变量存在于堆内存的对象中。
局部变量存在于栈内存的方法中。
(5) 成员变量随着对象的创建而存在,随着对象的消失而消失。
局部变量随着所属区域的执行而存在,随着所属区域的结束而释放。
(6) 成员变量都有默认初始化值。
局部变量没有默认初始化值。
四、面向对象——封装(Encapsulation)
(1) 封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
(2) 封装好处:
<1> 将变化隔离;
<2>便于使用。
<3>提高重用性。
<4> 提高安全性。
(3) 封装原则:
<1>将不需要对外提供的内容都隐藏起来。
<2>把属性都隐藏,提供公共方法对其访问。
(4) private:关键字
<1>用于修饰成员变量和成员方法。
<2>被修饰的内容在其他类中是不可以被访问的。
注意:私有仅仅是封装的一种体现而已。
<span style="font-size:18px;">/*
Person类。对Person的年龄进行私有化,让外界不能直接访问,对外提供公共的访问方式。
*/
class Person
{
//成员变量不赋值也可以进行运行,默认初始化值是null
String name;
//私有化年龄
private int age;
//对外提供公共设置的访问方式
public void setAge(int a)
{
//加入判断,使程序更为符合逻辑
if(a>=0 && a<=120)
age=a;
else
System.out.println("年龄不合法法");
}
//对外提供公共的获取方法
public int getAge()
{
return age;
}
//人可以说出自己的名字和年龄
public void speak()
{
System.out.println("name="+name+"...age="+age);
}
}
//Person测试类
class PersonTest
{
public static void main(String[] args)
{
Person p = new Person();
//对p对象的name属性进行赋值。
//p.age=-20//age被直接访问有安全隐患,有非法数据,加关键字private,age默认值是0
//p.setAge(-20);失败,因为不符合Person类中年龄的设置规则。
p.name="X";
//对p对象的age进行设置。
p.setAge(20);
//调用p对象的speak方法,打印自己的姓名和年龄。
p.speak();
}
}
</span>
五、构造函数
构造函数:构建创造对象时调用的函数。
(1) 构造函数特点:
<1>函数名与类名相同
<2>不用定义返回值类型
<3>没有具体的返回值。
(2) 构造函数作用:给对象进行初始化。创建对象都必须要通过构造函数初始化。一个类中如果没有定义过构造
函数,那么该类中会有一个默认的空参数构造函数。 如果在类中定义了指定的构造函数,那么类中的默认
构造函数就没有了。
(3) 注意:
<1> 默认构造函数的特点。
<2>多个构造函数是以重载的形式在在的。
(4) 一般函数和构造函数什么区别呢?
构造函数:对象创建时,就会调用与之对应的构造函数,给对象进行默认初始化。
一般函数:对象创建后,需要函数功能时才调用。(函数只有被调用才执行)
构造函数:对象创建时,只调用一次。
一般函数:对象创建后,可以被调用多次。
(5) 什么时候定义构造函数呢?
在描述事物时,该事物已存在就具备一些内容,这些内容都定义在构造函数中。
构造函数可以有多个,用于对不同的对象进行针对性的初始化。
多个构造函数在类中是以重载的形式来体现的。
(6) 构造函数的小细节:
当一个类中没有定义构造函数时,系统会默认给该类加入一个空参数的构造函数Person(){}
当在类中自定义了构造函数后,默认的构造函数就没有了
class Person
{
String name;
int age;
Person(){}
Person(String name,int age)
{
/*这里先穿越时空一下,等下会说到this关键字*/
this.name=name;
this.age=age;
}
public void speak()
{
System.out.println("name="+name+"...age="+age);
}
}
class Person
{
public static void main(String[] args)
{
Person p2 = new Person("小强",10);
p.speak();
}
public static void show()
{
System.out.println("cry");
}
}
(7) 构造函数内存图解:
(8) 构造代码块
构造函数块作用:给所有对象进行初始化。
对象一建立就运行,而且优先于构造函数执行和构造函数的区别:
构造代码块是给所有对象进行统一初始化。
而构造函数是给对应的对象进行初始化。
构造代码块中定义的是不同对象共性的初始化内容。
总结:构造代码块和构造函数共性的地方就是当对象创建时,就给对象进行初始化一次。
class Person
{
{
System.out.println("欢迎,我是构造代码块!");
}
//考虑到每个对象都是需要一个国籍,所以把国籍定义为共享对象。(等下会学到哦)
private static String contry = "cn";
private int age;
Person(int age)
{
this.age=age;
}
private boolean compare(Person p)
{
return this.age==p.age;
}
public void speak(Person p)
{
boolean b = compare(p)
System.out.println("年龄:"+b+"...国籍:"+contry);
}
}
class CompareAge
{
public static void main(String[] args)
{
Person p1 = new Person(20);
Person p2 = new Person(21);
p1.speak(p2);
}
}
六、this关键字
特点: this代表其所在函数所属对象的引用。
换言之:this代本类对象的引用。
什么时候使用this关键字呢?
当在函数内需要用到调用该函数的对象时,就用this。
当成员变量和局部变量重名,可以用关键字this来区分。
this:代表对象。代表哪个对象呢?当前对象。
this:就是所在函数所属对象的引用。
简单说:哪个对象调用了this所在的函数,this就代表哪个对象。
this的原理图解:
注意: this也可以用于在构造函数中调用其他构造函数。
this只能定义在构造函数的第一行。因为初始化动作要先执行。
构造函数间调用只能用this。
super关键字
如果要在函数内访问类中的同名成员变量,用super进行区分。
注意:每个类身上都是一个隐式的super();那么这个空参数的super构造函数是哪个呢?查阅API发现是 Object,他是所有类的父类。
七、静态修饰符:static
(1) 用法:
是一个修饰符,用于修饰成员(成员变量,成员函数),不能用于修饰局部。当成员被静态修饰后,就多了
一个调用方式,除了可以被对象调用外,还可以直接被类名调用。类名.静态成员。特有数据随着对象存储,放在堆内
存中,共有数据用static,存放在共享区(方法区)。
(2) static特点:
<1>随着类的加载而加载,随着类的消失而消失。说明他的生命周期最长。
<2>优先于对象存在,静态是先存在的,对象是后存在的。
<3>被所有对象共享
<4>可以被类名调用实例变量和类变量的区别
存在位置 类变量随着类的加载而存在于方法区中。 实例变量随着对象建立而建立存在于堆内存中。
生命周期 类变量生命周期最长,随着类的消失而消失。 实例变量生命周期随着对象的消失而消失。
(3) 静态使用注意事项
<1>静态方法只能访问静态成员(变量,函数) 非静态方法既可以访问静态也可以访问非静态。
<2>静态方法中不可以定义this,super关键字, 因为静态优先于对象存在。
<3>主函数是静态的。
(4) 静态有利有弊
利处:对对象的共享数据进行单独空间的存储, 节省空间,没必要每个对象都存在一份。 可以直接被类名调用。
弊端:生命周期过长,访问出现局限性。(静态只能访问静态)。
程序示例:
<span style="font-size:18px;">class Person
{
String name;//成员变量,实例变量
static String country="CN";//静态的成员变量,类变量。
public static void show()
{
System.out.println("::::"+country);
}
}
class StaticDemo
{
public static void main(String[] args)
{
Person p=new Person();
p.name="zhangsan";
p.show();
System.out.println(Person.country);
Person.show();
}
}</span><span style="font-size: 16px;">
</span>
(5) 静态代码块
格式:
static
{
静态代码块中的执行语句;
}
特点:
随着类的加载而加载,只执行一次。并优先于主函数。用于给类进行初始化。
(6) 静态的使用
什么时候使用静态?
要从两反面入手静态修饰的内容有成员和函数什么时候定义静态变量(类变量)和函数当对象中出现共享数
据(数值,name等是属性)时,该数据被静态所修饰。对象中的特有数据要定义成非静态,存在于堆内存中。什么
时候定义静态函数?当功能内部没有访问到非静态数据(即对象的特有数据)时, 那么该功能可以定义为静态的。
(7) 静态的应用
每个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用。虽然可以通过建ArrayTool
的建立使用这些工具方法,对数组进行操作。
(1)对象是用于封装数据的,可是ArrayTool对象并未封装特有数据。
(2)操作数组的每一个方法都没有用到ArrayTool对象中的特有数据。
(3)这时就要考虑,让程序更严谨,是不需要对象的。可以将ArrayTool中的方法都定义成static的。直接通过
类名调用即可。 将方法静态后,可以便于使用,但是该类还是可以被其他程序建立对象的 可以通过将构造函数私有
化完成。一个类中默认会有一个空参数的构造函数,这个默认的构造函数的权限和所属类一致。如果类被public修
饰,那么默认的构造函数也带public修饰符如果类没有被public,那么默认的构造函数,也没有public修饰。也就是说
默认构造函数的权限是随着类的变化而变化的。
程序示例:
<span style="font-size:18px;">class ArrayTool
{
private ArrayTool(){}
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];
}
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];
}
public static 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);
}
}
}
}
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++)
{
if(arr[y]>arr[y+1])
{
swap(arr,y,y+1);
}
}
}
}
private static void swap(int[] arr,int a,int b)
{
int temp=arr[a];
arr[a]=arr[b];
arr[b]=temp;
}
public static void printArray(int[] arr)
{
System.out.print("[");
for(int x=0;x<arr.length;x++)
{
if(x!=arr.length-1)
System.out.print(arr[x]+",");
else
System.out.println(arr[x]+"]");
}
}
}
</span>
<span style="font-size:18px;">
</span>
八、主函数
主函数是一个特殊的函数。作为程序的入口,可以被JVM调用。
主函数的定义:
public:代表着该函数访问权限是最大的。
static:代表主函数随着类的加载就已经存在了。
void:主函数没有具体的返回值。
main:不是关键字,但是是一个特殊的单词,可以被JVM识别。
(String[] arr):函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数组。
args:arguments 参数 。唯一可以更改的地方。
主函数是固定格式的:被JVM识别。
九、设计模式
解决某一类问题最行之有效的方法,Java中23种设计模式。
(1) 单例设计模式(Singleton):解决一个类在内存中只存在一个对象 ,比如对于多个程序使用同一个配置信息对 象时,就需要保证该对象的唯一性。
想要保证对象唯一:
为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象;
还为了让其他程序可以访问到该类对象,只好在本类中自定义一个对象;
为了方便其他程序对自定义对象的访问, 可以对外提供一些访问方式;
单例设计模式之饿汉式
Single类一进内存,就已经创建好了对象,简单的说就是一上来就吃。
思路:
将构造函数私有化;
在类中创建一个本类对象;
提供一个公共的访问方法,可以获取到该类对象;
步骤:
class Single
{
//将构造函数私有化
private Single(){}
//在类中创建一个本类对象
private finla static Single single =new Single();
//提供一个公共的访问方法,可以获取到该类对象
public static Single getInstance()
{
return single;
}
}
(2) 单例设计模式之懒汉式
对象是方法被调用时才初始化,也叫对象的延时加载
Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象。
步骤:
class Single
{
//将构造函数私有化
private Single(){}
private static Single single =null;
public static Single getInstance()
{
if(single==null)
{
synchronized(Single.class)
{
if(single==null)
single =new Single();
}
}
return single;
}
}
(3) 为什么有饿汉式还会有懒汉式?
原因就是对了面试,因为面试都是考懒汉式,因为要考虑到了多线程安全问题,使程序更加严谨。
实际开发中用饿汉式,因为在考虑多线程时会比较安全,懒汉式的解决安全问题的方法,双重判断,加入锁。
总结:
饿汉式:一上来就对对象初始化。 浪费一点点内存,因为不调用也执行嘛。
懒汉式:对象调用方法时,才初始化,也叫做对象的延时加载。
一点点内存都省,因为只有调用才占内存嘛。 习惯成自然,养成良好的节约内存习惯,对日后开发还
有很有帮助滴。我不知道大家是不是这样,反正我是这样了。