您的位置:首页 > 编程语言 > Java开发

Java从小白到大佬(面向对象第二部分)

2019-02-20 10:45 183 查看

1.创建对象的具体流程

1.javac xxx.java 将源代码进行编译,生成若干个字节码文件(.class)
2.java xxx 将名为xxx的.class文件和其相关的.class文件加载到虚拟机中等待运行(具体加载到方法区)
3.虚拟机在静态方法去中找xxx这个字节码中的静态主函数(main),如果没有直接报错(没有主函数函数无法执行);如果有则将主函数的代码加载到栈中,然后开始程序的运行

函数由虚拟机直接调用,不需要创建对象调用

4.在栈里面的函数空间中 拆关键引用数据类型的变量
5.在堆内存中开辟空间,分配地址,准备创建对象
6.对成员变量进行默认初始化
7.相应构造函数进栈,同时对成员变量进行显示初始化
8.按照构造函数的内容,对成员变量进行针对性初始化
9.构造函数弹栈,将对象空间的地址分给变量

2.代码块{}

2.1.静态代码块

格式:

static {
函数体;
}

静态代码块随着类的加载只执行一次,且优先于构造函数执行。所以静态代码块有时候可以用来处理一些成员变量。

2.2.构造代码块

{
方法体;
}

构造代码块随着对象的加载,创建一次执行一次。

2.3.局部代码块

函数和语句都叫局部代码块;

3.继承

java面向对象的三大特点:封装,继承,多态

3.1.什么时候可以继承?

当我们在描述一些事物时,发现有些事物具有重复的属性和行为,那么就可以将这些重复的东西进行抽取。
抽取出来的类:父类
原来的类: 子类
两者的关系:子类继承于父类

所有类的最终父类都为object类

3.1.1.代码实现继承要用到super关键字

有一个(父类)图形类figure,一个圆类circle(子类),所有图形都有一个名字name,所有的图形都有计算周长的方法getPerimeter();

class Figure{
String name;
public void getPerimeter();
}
class Circle extends Figure{
public Figure(){//创建无参构造函数
String name=super.name;//调用父类的变量
super.getPerimeter();//调用父类的方法
}
}

注意:
1.java中的类只能是单继承关系,只有接口可以多继承
2.不要随意的继承其他类,避免逻辑错误
3.在继承时变量支持就近引用。(子类局部>子类成员>子类静态>父类成员>父类静态)

3.1.1.1.super关键字的说明

super关键字的用法与this相同,但是super关键字不代表父类对象的引用,他只代表父类在堆方法区的存储位置。

3.1.2.注意事项

1.如果父类的构造函数private私有化,子类无法创建对象
解决:父类必须提供一个子类能够访问的构造函数
2.如果父类的构造函数被显示初始化,子类与父类中不一样的构造函数则无法继承父类
解决:子类得写出来一个与父类一样的构造函数
3.子类对父类继承的函数在子类中实现,其实就是子类对方法的重写。

3.1.2.1.重写的目的

子类对父类的函数有改进或者功能有增强
重写时子类的权限要高于父类:public>protected>默认>private

静态成员函数不存在重写

3.2.栈的两种实现(线性栈/链栈)

3.2.1.线性栈

代码实现:

public class StackDemo {
public static void main(String[] args) {
Array arr=new Array();
arr.print();
for(int i=0;i<6;i++) {
arr.push(i);
}
arr.print();
}
}
class function{
public void push(int ele) {};//一个元素进栈
public int pop() {return -1;}; //一个元素出栈
public int peek() {return -1;};//获取当前栈顶元素
public int size() {return -1;};//获取当前数组的有效长度
public void clear() {};//清空当前栈
public void print() {};//打印栈类元素
}
class Array extends function{
private int size;//数组的有效长度
int [] array;//容器
public Array() {
this(10);//如果创建有参对象则capacity为有参对象创建时传入的值,如果没有则capacity=10
}
public Array(int capacity) {
array=new int[capacity];
this.size=0;
}
public void push(int ele) {
if(size==array.length) {
resize(array.length*2);
}
array[size]=ele;
size++;
}
public int peek() {
return array[size-1];
}
public int getCapacity() {
return array.length;
}
public void print() {
if(size==0) {
System.out.println("bottom[]top :"+size()+"/"+getCapacity());
}else {
for(int i=0;i<size;i++) {
if(i==0) {
System.out.print("["+array[i]+",");
}else if(i==size-1) {
System.out.print(array[i]+"]");
}else {
System.out.print(array[i]+",");
}
}
}
}
public int pop() {
if(size==0) {
System.out.println("栈为空!");
return -1;
}
int ele=array[size-1];
size--;
return ele;

}
public int size() {
return size;
}
public void clear() {
size=0;
int [] newArr=new int [0];
array=newArr;
}
private void resize(int num) {
int [] newArray=new int[num];
for(int i=0;i<Math.min(array.length, newArray.length);i++) {
newArray[i]=array[i];
}
array=newArray;
}
}

3.2.2.链栈

代码:

public class StackDemo {
public static void main(String[] args) {
Link l=new Link();
for(int i=1;i<10;i++) {
l.push(i);
}
l.print();
}
}
abstract class function{
abstract public void push(int ele);//一个元素进栈
abstract public int pop() ; //一个元素出栈
abstract public int peek();//获取当前栈顶元素
abstract public int size();//获取当前数组的有效长度
abstract public void clear();//清空当前栈
abstract public void print();//打印栈类元素
}
class Link extends function {
private int size;
private Node head;
public Link() {
this.size=0;
this.head=new Node();//初始化头结点(头结点不需要传数值,只需要知道下一跳的地址)
}
/*public Link(int [] list) {
this();//无参构造器初始化,就是将头结点初始化
//串链表
for(int i=1;i<10;i++) {
push(list[i]);
}
}*/
public void push(int e) {
Node p=new Node(e,null);//创建链表元素p
p.next=head.next;
head.next=p;
//head.next=new Node(e,head.next)
size++;
}
private boolean isEmpty() {//判断栈是否为空?
if(size==0&&head.next==null) {
return true;
}else {
return false;
}
}
public int pop() {
if(isEmpty()) {
System.out.println("栈为空!");
return -1;
}
Node p=head.next;
int e=p.ele;
head.next=head.next.next;
p=null;
return e;
}
public int peek() {
return isEmpty()?-1:head.next.ele;
}
public int size() {
return size;
}
public void clear() {
head=null;
size=0;
}
public void print() {
if(isEmpty()) {
System.
29f1a
out.println("栈为空");
}else {
String s="top [";
Node p=head;
while(true) {
if(p.next!=null) {
s=s+p.ele+",";
p=p.next;
}else {
s=s+p.ele+"] bottom";
break;
}
}
System.out.println(s);
}
}
}
class Node{
int ele;
Node next;
public Node() {
this.ele=0;
this.next=null;
}
public Node(int ele,Node next) {
this.ele=ele;
this.next=next;
}
}

3.3.抽象类

3.3.1.什么是抽象类?

在继承的层次结构中,每一个新的子类都使类变得越来越明确和具体。如果从一个类追溯到父类,类有时候就会变得不合乎日常逻辑。类的设计应该确保父类包含子类的所有特征。有时候一个父类设计的非常抽象,以至于没有任何具体的实例,这样的类叫做抽象类。
一般的抽象类的格式:

权限修饰符 abstract class 抽象类名{
权限修饰符 abstract 函数();
}

3.3.2.特征

抽象类必须含有抽象函数,类名前必须有abstract, 子类有两种情况:要么在类中实现抽象方法,要么也写成抽象类。

将类的实现和使用分离(比如说有一个风扇父类,有好多的风扇子类,每个风扇都可以吹风但是每个风扇吹出来的风速不一样,
则风扇父类就可以抽取这个吹风功能)
abstract class fan{//fan类为抽象类
public abstract void chuifeng();
}
class fan1 extends fan{
public void chuifeng(){
System.out.println();
}
}

注意:父类抽出了几个抽象函数,子类在实现的时候应该有完全相同的函数(此处子类的函数其实是对父类函数的重写)

注意事项:
1.抽象类有构造函数,有成员变量,有成员函数,有静态函数和静态变量
2.抽象类不可以创建对象(但是不代表不能创建对象)
3.抽象类和一般类的区别在于:抽象类有abstract关键字和抽象函数
4.抽象类不能和那些关键字共存?
final 修饰函数表示函数不可以被重写 修饰类表示类不能被继承
private 私有化之后不能被其他类所调用
static 静态不能被重写 由于静态优先于对象加载进方法区

3.4.接口interface

接口是一种和类相似的结构,只包含常量和抽象函数。即当一个抽象类中所有的函数都是抽象函数,则可以用接口表示
接口在许多方面和抽象类相似,但是接口的目的是指明相关或者不相关的类的多个对象的共同行为。
一般格式:

修饰符 interface 接口名{
/**  常量声明 */public static final 变量名;
/**  方法签名*/
}

3.4.1.接口创建的规范

1.所有的变量都是public static final
2.没有构造方法,接口不能用new实例化
3.所有方法都是公共的抽象实例方法
4.类A调用接口B之后就相当于A是B的子类,这种情况下可以将接口看成是一个抽象类

3.4.2.调用接口implements

如果有一个接口A,接口B已经被定义,则类word调用接口A和B为:
class word implements A,B{

}

1.类与类之间有单继承关系,即一个子类只能继承一个父类
2.类与接口之间有多实现关系,即一个类可以使用多个接口
2.接口与接口之间有多继承关系,即一个接口可以使用多个其他接口

3.4.3.匿名实现子类的匿名对象

对于如下代码所示,Button类是一个手机APP开关类,开关只会在当前情况下使用一次,所以使用匿名实现子类的匿名对象比较合适。

3.5.多态

这里我们要明白,一个类实际上是在定义一种类型。子类定义的类型称为子类型,父类定义的类型称为父类型,继承关系使得一个子类继承父类的特征,并可以附加一些新的特征。每个子类的实例都是其父类的实例,但是父类的实例不一定会是子类的实例。比如:每一个圆都是一个集合对象,但是不是每一个几何对象都是圆。

所以,多态意味着父类型的变量可以引用子类型的对象。且多态一定是在有继承关系的类实现的。
格式:

父类型 变量名=new 子类型();
Geometic circle=new Circle();//这里的circle指的是Circle类创建出来的对象的引用
class Geometic{}
class Circle extends Geometic{}

注意:
1.成员变量在多态中的特点:只能访问父类的成员变量
2.成员函数在多态中的特点:如果子类有重写函数,则调用子类重写的函数;如果没有则调用父类的函数。子类的特有不可被调用
3.静态变量在多态中的特点:只能访问父类的静态变量
4.静态函数在多态中的特点:只能访问父类中的静态函数

3.5.1.单线程下的单例模式

单例模式:该类只能创建一个对象
1.外界不能直接创建对象-构造函数私有化
2.对象在内部创建,即在内部new 对象。
3.由于该对象有时候需要外部访问,需要get
4.getXXX不能为成员函数,所以必须static

3.5.1.1.饿汉式

main(){
Demo d1=Demo.getDemo();
Demo d2=Demo.getDemo();
System.out.println(d1==d2);//输出true 因为全局Demo只创建出来一个对象d

}
class Demo{
private static Demo d=new Demo();//保证全局只有一个对象d
private Demo(){}//构造函数私有化
public static Demo getDemo(){ //成员函数静态化,保证getDemo()不会成为成员函数。
return d;//返回对象d
}
}

3.5.1.2.饱汉式

class Single{
private static Single s=null;   //对对象s做一次判断
private Single(){}
public static Single getSingle(){
if(s==null){
s=new Single();
}else{
return s;
}
}
}

3.5.2.代理模式

类Agency和类Bb之间有一个类Aa联系,Aa作为中间人知道Bb的一切,那么就可以在Agency中创建Aa的对象指向Bb(Cc同理)

package inHerit;

public class Agency {
public static void main(String[] args) {
Aa a=new Aa();
a.run();
}
}
class Aa implements X{
Bb b=new Bb();
public void run() {
b.run();
}
}
class Bb implements X{
Cc c=new Cc();
public void run() {
c.run();
System.out.println("B can run");
}
}
class Cc implements X{
public void run() {
System.out.println("C can run");
}
}
interface X{
public void run();
}

3.5.3.内部类

在描述一个事物A(class A)的时候发现A之中还有另一个事物a(class a),则将a称为内部类

class A{
class B{

}
}

注意:
1.内部类为外部类的非静态成员
2.内部类中一旦有静态(不管是静态函数还是静态变量),则内部类必须是静态

class Outer{
int num=10;
static class Inter{
int num=20;
static void show() {
int num=30;
System.out.println(num);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐