------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
面向对象(java核心)
对象:
1.基本概念:
*面向对象是相对面向过程而言
*面向对象和面向过程都是一种思想
*面向过程强调的是功能行为
*面向对象将功能封装进对象,强调具备了功能的对象
*面向对象是基于面向过程的
2.特征:1,封装 2 继承 3,多态
(万物皆对象)
以后开发过程,其实就是找对象使用,没有对象就创建一个对象。
找对象-建立对象-使用对象-维护对象的关系。
3.类和对象的关系:
类:对现实生活中事物的描述。
对象:就是这类事物实实在在存在的个体。
描述:提取对象中共性内容,对具体的抽象。
(映射到java中,描述就是class定义的类。)
(具体对象就是对应java在堆内存中用new建立实体。)
4.成员变量和局部变量:(作用范围不同)
*成员变量作用于整个类中。
*局部变量作用于函数中,或者语句中。
在内存中的位置:
*成员变量在堆内存中,因为对象的存在,才在内存中存在。
*局部变量,存在栈内存中。
5.区别:
*成员变量随着对象的创建而存在,随着对象的消失而消失。
*局部变量随着所属区域的执行而存在,随着所属区域的结束而释放。
*成员变量都有默认初始化值。
*局部变量没有默认初始化值。
6.匿名对象使用方式:
1)当对对象的方法只调用一次时,可以用匿名对象来完成,这样写比较简化。
2)可以将匿名对象作为实际参数进行传递。
匿名对象
new People().name="张三";相当于:People p=new Peolple();p.name=”张三”;
匿名对象,有名对象区别
匿名对象创建完执行下一条语句前就销毁了,即是无意义的调用属性,用在只调用对象的方法,一次时,比较简化(调用属性一般是没意义的),有名对象进行多个成员(属性,行为)调用
匿名对象可作为实际参数进行传递
封装(Encapsulation):是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
1.封装好处:
1)将变化隔离;
2)便于使用。
3)提高重用性。
4)提高安全性。
2.封装原则:
*将不需要对外提供的内容都隐藏起来。
*把属性都隐藏,提供公共方法对其访问。
3.private:关键字
A:用于修饰成员变量和成员方法。
B:被修饰的内容在其他类中是不可以被访问的。
注意:私有仅仅是封装的一种体现而已。
构造函数:
A.构造函数特点:
1)函数名与类名相同。
2)不用定义返回值类型。
3)不可以写return语句。
B.构造函数:构建创造对象时调用的函数。
C.构造函数作用:给对象进行初始化。
创建对象都必须要通过构造函数初始化。
*一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数。
*如果在类中定义了指定的构造函数,那么类中的默认构造函数就没有了。
注意:
1.默认构造函数的特点。
2.多个构造函数是以重载的形式在在的。
D.一般函数和构造函数什么区别呢?
*构造函数:对象创建时,就会调用与之对应的构造函数,给对象进行默认初始化。
*一般函数:对象创建后,需要函数功能时才调用。(函数只有被调用才执行)
*构造函数:对象创建时,只调用一次。
*一般函数:对象创建后,可以被调用多次。
E.什么时候定义构造函数呢?
*在描述事物时,该事物已存在就具备一些内容,这些内容都定义在构造函数中。
*构造函数可以有多个,用于对不同的对象进行针对性的初始化。
多个构造函数在类中是以重载的形式来体现的。
F.构造代码块
1.构造函数块作用:给所有对象进行初始化。
2.对象一建立就运行,而且优先于构造函数执行和构造函数的区别:
构造代码块是给所有对象进行统一初始化; 而构造函数是给对应的对象进行初始化。
3.构造代码块中定义的是不同对象共性的初始化内容。
总结:构造代码块和构造函数共性的地方就是当对象创建时,就给对象进行初始化一次。
注意:构造代码块,提高效率,由{}括起来的代码
构造代码块的作:让变量在内存中尽可能快的消失,提高效率,把所有构造方法中的共同 定义在构造代码块中,提高代码的复用性,优先于构造方法执行。
*局部代码块定义在方法中
关键字(this super static)
A.this:关键字
1)特点:this代表其所在函数所属对象的引用。
this代本类对象的引用。
2)什么时候使用this关键字呢?
*当在函数内需要用到调用该函数的对象时,就用this。
*当成员变量和局部变量重名,可以用关键字this来区分。
总结:哪个对象调用了this所在的函数,this就代表哪个对象。
注意:
1.this也可以用于在构造函数中调用其他构造函数。
2.this只能定义在构造函数的第一行。因为初始化动作要先执行。
3.构造函数间调用只能用this。
代码示例:
class Person
{
private String name;
private int age;
Person(int age)//局部变量时age,成员变量也是age
{
this.age = age;//这里用this表示调用构造方法的对象
}
Person(String name)
{
this.name = name;
}
Person(String name,int age)
{
this(name);//this.name = name;
this.age = age;
}
public void speak()
{
System.out.println("name="+name+"...age="+age);
show();
}
public void show()
{
System.out.println(this.name);
}
}
class Test
{
public static void main(String args[])
{
Person p1 = new Person(20);
Person p2 = new Person("张三");
Person p13 = new Person("李四",21);
}
}
B.super关键字
如果要在函数内访问类中的同名成员变量,用super进行区分。
注意:每个类身上都是一个隐式的super();那么这个空参数的super构造函数是哪个呢?查阅API发现是Object,他是所有类的父类。
C.static关键字
用于修饰成员(成员变量和成员函数)
1.被修饰后的成员具备以下特点:
1)随着类的加载而加载
2)优先于对象存在
3)被所有对象所共享
4)可以直接被类名调用
2.static特点:
1)static是一个修饰符,用于修饰成员。(成员函数,成员变量)
2)static修饰的成员被所有的对象所共享。
3)static优先于对象存在,因为static的成员随着类的加载就已经存在了。
4)static修饰的成员多了一种调用方式,可以直接被类名调用。类名.静态成员。
5)static修饰的数据是共享数据,对象中存储的是特有数据。
3.成员变量和静态变量的区别?
1)两个变量的生命周期不同。
*成员变量随着对象的创建而存在,随着对象的被回收而释放。
*静态变量随着类的加载而存在,随着类的消失而消失。
2)调用方式不同。
*成员变量只能被对象调用。
*静态变量可以被对象调用,还可以被类名.调用。
3)别名不同。
*成员变量也称为实例变量。
*静态变量称为类变量。
4)数据存储位置不同。
*成员变量存储在堆内存的对象中,所以也叫对象的特有数据。
*静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。
4.什么时候该用static呢?
如果某个内容是所有对象共享的,就用静态修饰。
5.什么时候使用静态成员和函数呢?
要从两方面下手:因为静态修饰的内容有成员变量和函数
6.什么时候定义静态变量(类变量)呢?
当对象中出现可共享的数据时,该数据被静态修饰。
对象中的特有数据要定义成非静态存在于堆内存中。
7.什么时候定义静态函数呢?
当功能内部没有访问到非静态数据,或者对象的特有数据, 那么该功能可以定义成静态的
注意:
1.静态方法可能访问静态成员类名.静态成员。
2.静态方法中不可以写this,super关键字,因为静态先于对象操作
静态有利有弊:
利处: 对对象共享的数据进行单独空间的存储,没有必要每个对象都存一份 ,可以被直 接被类名调用。
弊端:生命周期过长,访问出现局限性(静态虽好,只能访问静态)
3.主函数是静态的
public static void main(String[] args)
主函数特殊之处:
1)格式是固定的。(除了args这个数组名字可以变,其他不行)
2)被Jvm所识别和调用。
public:因为权限必须是最大的。
static:不需要对象的,直接用主函数所属类名调用即可。
void:主函数没有具体的返回值。(因为返一个值给虚拟机,虚拟机也害怕啊!是不是虚拟机没有内存存放)
main:函数名,不是关键字,只是一个Jvm识别的固定的名字。
String[] args:这是主函数的参数列表,是一个数组类型的参数,而且元素都是字符串类型。
8.什么时候定义静态函数?
当功能内部没有访问到非静态数据(对象的特有数据),那么该功能可以定义成静态的。(说了也不清楚,下面来一个静态的应用)
9.静态代码块:
格式:
static{
静态代码块中的执行语句
}
特点:随着类的加载而执行,只执行一次,并优先于主函数
10.对象初始化的顺序:
静态代码块——>静态主函数——>构造代码块——>构造函数
11.静态的应用-工具类
->>
当一个类中创建了另一个类的对象,编译的时候会同时编译两个类文件;
/*
每一个应用程序中都有共性的功能,
可以将这些功能进行抽取,独立封装,以便复用。
虽然 可以通过建立ArrayTool的对象使用这些工具方法,对数组进行操作。
发现问题:
对象是用于封装数据的,可是ArrayTool对象并未封装特有(非公性)数据。
操作数组的每一个方法度没有用到ArrayTool对象中的特有数据。
考虑让程序更严谨,不需要对象。
直接将这些方法定义成静态的,直接通过类名调用即可。
方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的,
为了更为严谨,强制让该类不能建立对象,
可以通过将默认的构造函数私有化完成。
空参数的构造函数不一定是默认构造函数,默认的是看不见的,写了就不是默认的了。
class Demo
{
Demo(){}:当你定义了空参数的构造函数,就不是默认的了,而是自定义构造函数了。
}
1)*/class ArrayTool//工具类,通常是静态的方法
{
private ArrayTool(){};//将默认的构造函数私有化,对方不能建立对象。
//获得最大值
public static int getMax(int[] arr)
{
int max=0;
for(int x=1; x<arr[max];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[min],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.print(arr[x]+"]");
}
}
}
2)class ArrayToolDemo //调用工具类的方法
{
public static void main(String[] args)
{
int[] arr={3,6,89,43,56};
int max=ArrayTool.getMax(arr);
System.out.println("Max="+max);
//能够创建对象,因为工具类有个默认的空构造函数。只要有属性或行为,就可以创建对象。
/*ArrayTool tool=new ArrayTool();//此对象没必要生成,将工具类的方法改为静态
int max=tool.getMax(arr);
System.out.println("Max="+max);
tool.printArray(arr);
tool.selectSort(arr);
tool.printArray(arr);
*/
}
}
继承:
概述:Java语言中,Java只支持单继承,不支持多继承。
一个类只能有一个子类(extends) 一个父类(super),不允许多个,容易有安全隐患。
多继承隐患:
(1)比如,同时继承两个类,但是两个类中有连个同名函数。
(2)但是Java保留了这种机制,并用另一种体现形式来完成表示,叫做多实现。
(3)Java支持多层继承,也就是一个继承体系,B继承A,C继承B,这样C就既有了A的功能,又有了B的功能,这就是多继承。
使用一个继承体系的功能
(1)要想使用体系,先查阅体系父类的描述,因为父类中,定义的是该体系中共性的功能。
(2)通过了解共性功能,就可以知道该体系的基本功能。
(3)那么这个体系已经可以基本使用了。
在具体调用时,要创建最子类的对象,还是父类对象?
(1)有可能父类不能创建对象。
(2)创建子类对象可以使用更多功能,包括基本的也包括子类特有的。
总结:简单一句话,查阅父类功能,创建子类对象使用功能。
继承的出现(Extends):
1)提高了代码的复用性。
2)让类与类之间产生了关系。有了这个关系,才有了多态的特性。
注意:
*千万不要为了获取其他类的功能,简化代码而继承。
*必须是类与类之间有所属关系才可以继承,所属关系,父类、子类(is a)。
聚集关系:
类与类之间不只有继承关系,也有聚集(包括聚合和组合)关系。
聚合:球队由球员组成,球员是球队中的一个,球队中有球员。
组合:比聚合更紧密,心脏和身体的关系,不可分割。
子父类中变量的特点:
1)如果子类中出现非私有的同名成员变量时,子类要访问本类中的变量,用this。
2)子类要访问父类中的同名变量,用super。
3)super的使用和this的使用几乎一致,this代表的本类对象的引用,super代表的是父类对象的引用。
子父类中函数的特点(重写=覆盖):
1)当子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容,如同父类的函数被覆盖一样,这种情况是函数的另一个特性:重写(覆盖)。
2)当子类继承父类,沿袭了父类的功能到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致,这时,没有必要定义新功能,而是使用覆盖,保留父类的功能定义,并重写功能内容。
覆盖:子类覆盖父类,必须保证子类权限大于等于父类,才可以覆盖,否则编译失败。静态只能覆盖静态。
注意:重载只看同名函数的参数列表;重写 子父类方法要一模一样。
子父类中构造函数的特点:
1)在对子类对象进行初始化时,父类的构造函数也会运行。
那是因为子类的构造函数默认第一行有一条隐式的语句super();
super():会访问父类中空参数的构造函数,而且子类中所有的构造函数默认第一行都是super();
2)子类一定要访问父类中的构造函数,因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的,所以子类在对象初始化时 ,要先访问一下父类中的构造函数,如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。
注意:super语句一定要定义在子类构造函数的第一行。
继承弊端:打破了封装性。
子类的实例化过程:
结论: 子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
因为子类每一个构造函数内的第一行都有一句隐式super();
当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定 要访问父类中的构造函数;
当然,子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。子类中至少会有一个构造函数会访问父类中的构造函数。
代码块(面试题,理解)
(1)执行顺序:
静态代码块 --> 构造代码块 --> 构造方法
(2)注意事项:
静态代码块只执行一次
final关键字(最终值)
*可以修饰类、函数、变量。
*被 final 修饰的类,不可以被继承,为了并避免被继承,被子类复写功能。
*被 final修饰的方法。
*被final修饰的变量是一个常量,只能赋值一次,既可以修饰成员变量,也可以修饰局部变量。
*当在描述事物时,一些数据的出现 值是固定的,那么这时为了增强阅读性,都给这些值起个名字,方便于阅读, (而这个这不需要改变,所以加上final修饰。 )
比如 鹬怠?
*作为常量,敞亮的书写规范所有字母都大写,如果由多个单词组成,单词间通过 _ 连接。
*一般是public static final 。。。这么使用。
*内部类定义在类中的局部位置上时,只能访问该局部被 final修饰的局部变量。
多态:
概述:对象在不同时刻表现出来的不同状态 。
多态的前提:
a 类与类之间必须存在关系(要么继承extends,要么实现implements)
b 存在覆盖(重写)
C 父类引用指向子类对象
代码示例:
/*
基础班学生:
学习,睡觉。
高级班学生:
学习,睡觉。
可以将这两类事物进行抽取。
之前是指挥每一个对象去做事,现在是指挥一批对象去做事(指挥一批不同的动物吃饭);
*/
abstract class Student
{
public abstract void study();
public void sleep()
{
System.out.println("躺着睡");
}
}
class DoStudent//工具类
{
public void doSome(Student stu)
{
stu.study();
stu.sleep();
}
}
class BaseStudent extends Student
{
public void study()
{
System.out.println("base study");
}
public void sleep()
{
System.out.println("坐着睡");
}
}
class AdvStudent extends Student
{
public void study()
{
System.out.println(" adv study");
}
}
class DuoTaiDemo3
{
public static void main(String[] args)
{
DoStudent ds = new DoStudent();
ds.doSome(new BaseStudent());
ds.doSome(new AdvStudent());
//BaseStudent bs = new BaseStudent();
//bs.study();
//bs.sleep();
//AdvStudent as = new AdvStudent();
//as.study();
//as.sleep();
}
}
多态在父类中的成员特点:
成员变量:
编译:参考引用类型变量所属的类中是否有调用的成员变量,有—>编译通过,反之则失败。
运行时:参考引用类型变量所属的类中是否有调用的成员变量,并运行所属类中的成员变量。
总结:编译运行都参考等号左边。
成员函数(非静态):
编译:参引用型变量所属的类中的是否有调用的函数。有—>编译通过,没有,编译失败。
运行:参考的是对象所属的类中是否有调用的函数。
总结:编译看左边,运行看右边。因为成员函数存在覆盖特性。
静态函数:
编译:参考引用型变量所属的类中的是否有调用的静态方法。
运行:参考引用型变量所属的类中的是否有调用的静态方法。
注意(其实对于静态方法,是不需要对象的。直接用类名调用即可。)
多态的弊端:父类引用不能使用子类特有功能。
多态弊端的解决方案:Fu f = new Zi(); //向上转型
Zi z = (Zi) f; //向下转型
Zi z = new Zi();
多态的好处:可以提高代码的扩展性和可维护性。
代码示例:
class Fu
{
static int num = 5;
int num2 = 6;
void method1()
{
System.out.println("fu method_1");
}
void method2()
{
System.out.println("fu method_2");
}
static void method4()
{
System.out.println("static fu method_4");
}
}
class Zi extends Fu
{
static int num = 8;
int num2 = 9;
void method1()
{
System.out.println("zi method_1");
}
void method3()
{
System.out.println("zi method_3");
}
static void method4()
{
System.out.println("static zi method_4");
}
}
class Test
{
public static void main(String[] args)
{
Fu f = new Zi();
System.out.println(f.num);//编译运行看左边
Zi z = new Zi();
System.out.println(z.num);
f.method1();//编译看左边,运行看右边
f.method2();//编译看左边,运行看右边
//f.method3();//编译运行看左边,编译失败
f.method4();//编译运行看左边
/*Fu f = new Zi();
System.out.println(f.num);//编译运行看左边
f.method4();//编译运行看左边
Zi z = new Zi();
z.method4();*/
/*Zi z = new Zi();
z.method1();//覆盖父类
z.method2();//继承父类
z.method3();//覆盖父类
*/ }
}
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------