概述
在这一周的学习中,我学了面对对象这一章,这一章相比于C++多了许多新东西,同时这一章也是Java学习中的关键部分,所以我对此下了很大功夫。
面向对象具有三大特征:封装性、继承性和多态性,而面向过程没有继承性和多态性,并且面向过程的封装只是封装功能,而面向对象可以封装数据和功能。所以面向对象优势更明显。
目录
四.Java面对对象
this
super
Package
包
单例模式
类型转换
final
String类中常用的方法
抽象方法
抽象类
接口
内部类
a) 非静态内部类
b)静态内部类
匿名类
局部内部类
本地类
默认方法
四.Java面对对象
栈的特点如下:
1. 栈描述的是方法执行的内存模型。每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)
2. JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)
3. 栈属于线程私有,不能实现线程间的共享!
4. 栈的存储特性是“先进后出,后进先出”
5. 栈是由系统自动分配,速度快!栈是一个连续的内存空间!
堆的特点如下:
1. 堆用于存储创建好的对象和数组(数组也是对象)
2. JVM只有一个堆,被所有线程共享
3. 堆是一个不连续的内存空间,分配灵活,速度慢!
方法区(又叫静态区)特点如下:
1. JVM只有一个方法区,被所有线程共享!
2. 方法区实际也是堆,只是用于存储类、常量相关的信息!
3. 用来存放程序中永远是不变或唯一的内容。(类信息【Class对象】、静态变量、字符串常量等)
this
this的本质就是“创建好的对象的地址”! 由于在构造方法调用前,对象已经创建。因此,在构造方法中也可以使用this代表“当前对象” 。
C++中是this->name;
而在Java中为this.name=name;
super
可以用来修饰属性,方法,构造器
f(){}
super.f();
构造方法的第一句总是super()
1、当子类与父类有同名的属性时,可以通过super属性的方式调用父类中生命的属性。
2、当子类重写父类的方法后,在子类中若想调用父类中被重写的方法时,需用super.的方法
3、super修饰构造器,通过在子类中使用super列表参数的形式调用父类中制定的构造器
a、在构造器内部,super(参数列表)必须声明在首行
b、在构造器内部,this(参数列表)或super(参数列表)只能出现一个
c、当构造器中不显示的调用this(参数列表)或super(参数列表)默认调用父类中的空参 构造器
public childclass extends fatherclass{
public childclass(){
super();//默认的
System.out.println();
}
} //子->父->object
注意:在类中,用static声明的成员变量为静态成员变量,也称为类变量static成员变量只有一份。被该类的所有对象共享!!在static方法中不可直接访问非static的成员。
static修饰的成员变量和方法,从属于类。普通变量和方法从属于对象的。
没有static需要有对象才能调用。加static可直接调用,不用再new。
为什么this super不能用在static方法中
this : 代表当前自身类的对象,可以调用当前类的构造方法,成员变量和成员方法等
super : 代表对父类的引用 , 可以调用父类构造方法,成员变量和方法
因为static方法和类的实例(对象)是两码事,它只在类装载的时候初始化,被称作类级变量(属于类);而类的实例是在程序运行的时候(即Java命令的时候)初始化,被称作对象级变量(属于对象);
this表示这个类的当前实例,super表示父类的当前实例,static是属于类的,this是类的一个对象,
this指针是指向类的对象,在实例化对象时jvm会在堆区分配内存给一个具体的对象,this指针指向这个对象。而类中的static域始终是在静态区分配内存,this指向堆区,所以不能调用。
因此this super不能用在static方法中
Package
为了便于管理,将处理同一方面的问题的类放在同一个目录下,引入了包
包定义:
package 包名; //声明
package(包) 域名倒着写 cn.gst.oo
cn.gst.oo.User user=new cn.gst.oo.User();(有点繁琐) //使用其他包的类
//使用其他包的类,用import. import cn.gst.oo.User;
使用 import 导入单个类 import 包名+类名;
直接导入指定类 import example.Test;
使用 import 语句导入指定包下全部类 import example.*;
单例模式 : 只有一个实例存在,给别的类用
什么是单例模式?
1. 构造方法私有化
2. 静态属性指向实例
3. public static的 getInstance方法,返回第二步的静态属性
饿汉式单例模式:未使用就已经实例化。
//GiantDragon 提供了一个public static的getInstance方法,外部调用者通过该方法获取12行定义的对象,而且每一次都是获取同一个对象。 从而达到单例的目的。
private test(){
//通过私有化其构造方法,使得外部无法通过new 得到新的实例。
}
private static test instance = new test();//准备一个类属性,指向一个实例化对象。 因为是类属性,所以只有一个
public static txst getInstance(){
//public static 方法,提供给调用者获取定义的对象
return instance;
}
懒汉式单例模式:使用时才实例化。
private test(){
//私有化构造方法使得该类无法在外部通过new 进行实例化
}
private static test instance=null;
//准备一个类属性,用于指向一个实例化对象,但是暂时指向null
public static test getInstance(){
//public static 方法,返回实例对象
if(null==instance){
//第一次访问的时候,发现instance没有指向任何对象,这时实例化一个对象
instance = new test();
//返回 instance指向的对象
}
什么时候使用饿汉式,什么时候使用懒汉式:
饿汉式是立即加载的方式,无论是否会用到这个对象,都会加载。
懒汉式,是延迟加载的方式,只有使用的时候才会加载。
使用懒汉式,在启动的时候,会感觉到比饿汉式略快,因为并没有做对象的实例化。 但是在第一次调用的时候,会进行实例化操作,感觉上就略慢。
有比较充分的启动和初始化时间,就使用饿汉式,否则就使用懒汉式
类型转换:
子类转父类(向上转型),一定可以的
父类转子类(向下转型),所以要进行强转
instanceof 类名 判断一个引用所指向的对象,是否是父类,或者子类
(二元运算符,左边是对象,右边是类,当是右边类或子类创建的对象时,返回true,否则返回false)
Object obj = new String("
");
if(obj instanceof String){
//判断所指向的对象
String str = (String)obj;
System.out.println(str.charAt(0));
}else if(obj instanceof StringBuffer){
StringBuffer str = (StringBuffer) obj;
System.out.println(str.charAt(0));
}
向上转型:父亲引用指向子类对象或者 子类转为父类(小转大,不需要强转)
向下转型:子类引用指向父类对象 或者父类转子类(大转小,需强转)
C++在类中默认private,Java默认为default
修饰符 | 同一个类 | 同一个包 | 子类 | 所有类 |
private | √ | |||
default | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
final
1.修饰变量:被他修饰的变量不可改变,一旦赋了初始值,就不能被重新赋值
2.修饰方法:该方法不可被子类重写,但可以被重载
3.修饰类:修饰的类不能被继承。例如String,Math。
4.修饰引用:h引用被修饰成final,表示该引用只有1次指向对象的机会,依然通过h引用修改对象的属性值hp,因为hp并没有final修饰
final Hero h;
h =new Hero();
h =new Hero();//错误
h.hp = 5;
5.常量指的是可以公开,直接访问,不会变化的值
public static final int itemTotalNumber = 6;
① 首先介绍一下String类中常用的方法
1.在java中共有三种方法将两个字符串连接
第一种方法:使用+;
public static
String mergedString1(String string1,String string2) {
return
string1 + string2;
}
第二种方法:使用concat();
public static String mergedString2(String string1, String string2) {
return string1.concat(string2);
}
第三种方法:使用append();
public static
StringBuffer mergedString3(String string1, String string2) {
StringBuffer sb = new StringBuffer(string1);
return sb.append(string2);
}
2.判断两个String对象相等
String str1 = "the light";
String str2 = new String(str1);
System.out.println( str1 == str2); //false
str1和str2的内容一定是一样的!但是,并不是同一个字符串对象
String str1="gg";
String str2="gg";
System.out.println( str1 == str2); //true
//编译器发现已经存在现成的"the light",那么就直接拿来使用,而没有进行重复创建
3.通常比较字符串时,用equals
String str1="gg";
String str2="gg";
System.out.println(str2.equals(str1)); //true
4.提取字符 :charAt()
String s1="love";
System.out.println(s1.charAt(3)); //输出为e
5.字符串的长度:length()
String s1="love";
System.out.println(s1.length());
6.比较两个字符串(忽略大小写):equalsIgnoreCase()
String s1="A";
String s2="a";
System.out.println(s2.equalsIgnoreCase(s1)); //忽略大小写 A==a; true
7.字符串中是否包含:indexOf()
System.out.println(s1.indexOf("Java"));//检测字符串s1中是否包含Jav
String s1 = "core Java";
System.out.println(s1.indexOf("Java"));//检测字符串s1中是否包含Java。true
//若无返回-1。
8.替换 :replace()
String s1 = "core Java";
String s=s1.replace(' ','&');//将s1中空格换为&
9.是否以 ...开头startsWith()
String s1="How are you?";
System.out.println(s1.startsWith("How"));//是否以How开头
10.是否以...结尾:endsWith()
String s1="How are you?";
System.out.println(s1.endsWith("you"));//是否以you结尾
11.提取子字符串:substring()
String s=" ";
String s1="How are you?";
s=s1.substring(4);//提取子字符串,从4开始. //are you?
System.out.println(s);
String s=" ";
String s1="How are you?";
s=s1.substring(4,7);//提取子字符串,从[4,7),不包括7, //are
System.out.println(s);
12.转小写:toLowerCase()
String s1="H";
s=s1.toLowerCase();//.转小写
System.out.println(s);
//h
13.转大写:toUpperCase()
String s1="h";
s=s1.toUpperCase();//.转大写
System.out.println(s);
//H
14.去除收尾的字符串,中间不去:trim()
String s2=" How old are you!! ";
s=s2.trim(); //去除收尾的字符串,中间不去
System.out.println(s); //How old are you!!
System.out.println(s2);// How old are you!! //s2不变
抽象方法
使用abstract修饰的方法,没有方法体,只有声明。定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。
抽象类
包含抽象方法的类就是抽象类。通过abstract方法定义规范,然后要求子类必须定义具
实现。通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。
示例:
public abstract class Animal{
//规范子类
abstract public void shout();
public static void main(String[] args){
Animal a=new Animal();//错误
Animal a=new Dog();
}
} ; //子类必须实现
class Dog extends Animal{
public void shout(){
System.out.println();//必须有
}
}
为父类增加一个抽象方法 ,继承父类后,这些子类就必须提供不一样的抽象方法实现。
抽象类的使用要点:
1.有抽象方法的类只能定义成抽象类
2.抽象类不能实例化,即不能用new实例化
3.抽象化可以包含属性,方法,构造方法,但构造方法不能用来new实例,只能用来被子类调用
4.抽象类只能用来被继承
5.抽象方法只能被子类实现
实例化:只是单纯的把对象 new 一下就行了 例:Student st=new Student();这样就行了
初始化:是在实例化之后完成的,先实例化对象,只给对象属性赋值,然后初始化这个对象
在Java中引入了接口这个概念。
接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。全面地专业地实现了:规范和具体实现的分离。
抽象类还提供某些具体实现,接口不提供任何实现,接口中所有方法都是抽象方法。接口是完全面向规范的,规定了一批类具有的公共方法规范。
声明格式:
[访问修饰符]
interface 接口名
[extends
父接口1,父接口2…]
{
常量定义;
方法定义;
}
定义接口的详细说明:
1.访问修饰符:可以是默认或者public
2.接口名:和类名采用相同命名机制
3.extends:接口可以多继承
4.常量:接口中的属性只能是常量, int M=111;
总是:public static final修饰,不写也是
5.方法:接口中的方法只能是public abstract,不写也是
注意:接口内所有方法多是抽象化,不用再写abstract ,因此必须重写。
关键字: implements(接口)
java的类只有单继承,接口有多继承
抽象类和接口的区别:
区别1:子类只能继承一个抽象类,不能继承多个
子类可以实现多个接口
区别2:抽象类可定义public,protected,package,private。静态和非静态属性。final和非final属性。
但是接口中声明的属性,只能是public,静态,final的,即便没有显式的声明。
接下来介绍一些 内部类
在Java中内部类主要分为成员内部类(非静态内部类、静态内部类)、匿名内部类、局部内部类。
成员内部类(可以使用private、default、protected、public任意进行修饰。
a) 非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)
i. 非静态内部类必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。
ii. 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。
iii. 非静态内部类不能有静态方法、静态属性和静态初始化块。
iv. 外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例。
非静态内部类可以直接在一个类里面定义
实例化语法: new 外部类().new 内部类() 或 外部类对象.new 非静态内部类();
public class 外部类 {
...
// 非静态内部类,只有一个外部类对象存在的时候,才有意义
// 战斗成绩只有在一个英雄对象存在的时候才有意义
class 非静态内部类 {
...
public void 方法名() {
...
}
}
public static void main(String[] args) {
外部类 对象 = new 外部类();
// 实例化内部类
// 非静态内部类对象只有在一个外部类对象存在的时候才有意义
// 所以其实例化必须建立在一个外部类对象的基础之上
}
}
在内部类中使用外部成员变量: Outer.this.age 内部类名.this.外部成员变量。
在内部类中使用内部类的成员变量: this.age this.内部成员变量
在内部类中使用局部变量: age
b)静态内部类
i. 定义方式:
static
class
ClassName {
//类体
}
ii. 使用要点:
1. 当一个静态内部类对象存在,并不一定存在对应的外部类对象。 因此,静态内部类的实例方法不能直接访问外部类的实例方法。
2. 静态内部类看做外部类的一个静态成员。 因此,外部类的方法中可以通过:“静态内部类.名字”的方式访问静态内部类的静态成员,通过 new 静态内部类()访问静态内部类的实例。
在一个类里面声明一个静态内部类与非静态内部类不同,静态内部类的实例化 不需要一个外部类的实例为基础,可以直接实例化
除了可以访问外部类的私有静态成员外,静态内部类和普通类没什么大的区别
实例化语法:new 外部类.静态内部类();
匿名类
匿名类指的是在声明一个类的同时实例化它,使代码更加简洁精练
通常情况下,要使用一个接口或者抽象类,都必须创建一个子类
有的时候,为了快速使用,直接实例化一个抽象类,并“当场”实现其抽象方法。
既然实现了抽象方法,那么就是一个新的类,只是这个类,没有命名。
这样的类,叫做匿名类
public abstract class 外部类 {
...
public abstract void 方法();
public static void main(String[] args) {
外部类 对象 = new 外部类(){
//当场实现方法
public void 方法() {
...
}
};
对象.方法();
System.out.println(对象); //通过打印对象,可以看到这个对象属于&&这么一个系统自动分配的类名
}
}
注意: 1. 匿名内部类没有访问修饰符。
2. 匿名内部类没有构造方法。因为它连名字都没有那又何来构造方法呢。
//在匿名类中使用外部的局部变量,外部的局部变量必须修饰为final。
注:在jdk8中,已经不需要强制修饰成final了,如果没有写final,不会报错,因为编译器偷偷的帮你加上了看不见的final
局部内部类
局部内部类是定义在方法内部的,作用域只限于本方法。
public class 外部类{
public void 方法1() {
//作用域仅限于该方法
class 内部类 {
public void 方法2() {
...
}
}
new 内部类().方法2();
}
public static void main(String[] args) {
new 外部类().方法1();
}
}
本地类
本地类可以理解为有名字的匿名类
内部类与匿名类不一样的是,内部类必须声明在成员的位置,即与属性和方法平等的位置。
本地类和匿名类一样,直接声明在代码块里面,可以是主方法,for循环里等等地方
public abstract class 外部类 {
...
public abstract void 方法();
public static void main(String[] args) {
//与匿名类的区别在于,本地类有了自定义的类名
class 本地类 extends 外部类
public void 方法() {
//进行重写
}
}
本地类 对象
=new 本地类();
对象.方法();
}
}
默认方法是JDK8新特性,指的是接口也可以提供具体方法了,而不像以前,只能提供抽象方法。
public interface 接口名 {
public void 方法1();
default public void 方法2() {
//接口增加了一个默认方法2,这个方法有实现体,并且被声明为了default
...
}
}
最后
以上就是年轻乌龟为你收集整理的Java学习(第二周)四.Java面对对象final抽象方法抽象类的全部内容,希望文章能够帮你解决Java学习(第二周)四.Java面对对象final抽象方法抽象类所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复