1.this(当前对象的/或/构造器正在初始化的对象)
1.他在方法内部使用,即这个方法所属对象的引用
2.它在构造器内部使用,表示“该构造器正在初始化的对象”
3.this表示“当前对象的”//”this表示当前引用(注意不是当前对象)”,可以调用类的属性、方法和构造器
3.1 在类的方法中,我们可以使用“this.属性”或“this.方法”的方式,调用当前对象属性或方法,但 是通常情况下,我们都选择省略”this.”。特殊情况下,如果方法的形参和类的属性同名时, 我们必须显式的使用“this.变量”的方式,表明此变量是属性,而非形参。
public void setRadius(double radius) {
this.radius = radius;
}
public girl{
public int compare(Girl girl) {
return this.age - girl.age;//this:当前对象的 girl:形参girl
}
3.2 在类的构造器中,我们可以使用“this.属性”或“this.方法”的方式,调用当前正在创建的对象属性或方法,但是通常情况下,我们都选择省略”this.”。特殊情况下,如果方法的形参和类的属性同名时, 我们必须显式的使用“this.变量”的方式,表明此变量是属性,而非形参。
public Circle(double radius) {
this.radius = radius;
}
3.3 this调用构造器
A. 我们在类的构造器中,可以显式的使用“this(形参列表)”方式,调用本类中指定的其他 构造器
B. 构造器中不能通过”this(形参列表)”方式调用自己
C. 如果一个类中有n个构造器,则最多有 n -1 构造器中使用了”this(形参列表)”
D. 规定:”this(形参列表)”必须声明在当前构造器的首行
E. 构造器内部,最多只能声明一个”this(形参列表)”,用来调用其他的构造器
public Person(){//空参构造器
this.eat();
}
public Person(String name){
this();//调用上面的空参构造器
this.name = name;
}
public Person(String name){
this();//调用上面的空参构造器
this.age = age;
}
public Person(String name,int age){
this(age);//调用上面的带参构造器
this.name = name;
}
4.什么时候使用this关键字呢?
当在方法内需要用到调用该方法的对象时,就用this
具体的:我们可以用this来区分局部变量和属性。
this.name = name;//对象.属性,所以第一个是属性
2.super(父类的)
2.1 super调用属性和方法
2.1.1 我们可以在子类的方法或构造器中,通过使用”super.属性”或”super.方法”的方式,显示的调用父类中声明的属性或方法,但是,通常情况下,我们习惯省略”super.”
2.1.2 特殊情况,当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须是显式的使用”super.属性”的方式,表明调用的是父类中声明的属性。
public class Person{
int id = 1001;//身份证
}
public class Student extends Person{
int id = 1002;//学生证
public void Show(){
System.out.println("id = " + id);//1001
System.out.println("id = " + super.id);//1002调用父类属性id
}
}
2.1.3 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须是显式的使用”super.方法”的方式,表明调用的是父类中被重写的方法。
public class Person{
public void eat(){
System.out.println("人:吃饭");
}
public void walk(){
System.out.println("人:走路");
}
}
public class Student extends Person{
@Override
public void eat(){
System.out.println("学生:多吃有营养的食物");
}
}
public class SuperTest{
public static void main(String[] args){
Student s = new Student();
s.eat();//学生:多吃有营养的食物
super.eat();//人:吃饭
this.walk();//子类没有重写父类的方法,先在子类中找,没找到,再去父类找
super.walk();//直接去父类找
}
}
2.2 super调用构造器
2.2.1 我们可以在子列的构造器中显式的使用”super(形参列表)”的方式,调用父类中声明的指定的构造器
2.2.2 “super(形参列表)”的使用,必须声明在子类构造器的首行!
2.2.3 我们在类的构造器中,针对于”this(形参列表)”或”super(形参列表)”只能二选一,不能同时出现
public class Person{
public Person(String name,int age){
this.name = name;
this.age = age;
}
}
public class Student extends Person{
public Student(String name,int age){
super(name);
this.age = age;
}
public Student(String name,int age,String major){
super(name,age);
//this(name,age);//只能二选一
this.major = major;
}
}
2.2.4 在构造器的首行,没有显式的声明”this(形参列表)”或”super(形参列表)”,则默认调用的是父类中空参的构造器
public class Person{
public Person(){
System.out.println("我无处不在!");//证明调用了空参构造器
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
}
public class Student extends Person{
public Student(String major){
//super();//即使不写,默认调用此空参构造器
this.major = major;
}
}
public class SuperTest{
public static void main(String[] args){
Student s = new Student();
//执行会输出:我无处不在!
}
}
2.2.5 在类的多个构造器中,至少有一个类的构造器中使用了”super(形参列表)”,调用父类中的构造器
2.2.6 在调用子类构造器之前,会先调用父类构造器,当子类构造器中没有使用”super(参数或无参数)”指定调用父类构造器时,是默认调用父类的无参构造器,如果父类中包含有参构造器,却没有无参构造器,则在子类构造器中一定要使用“super(参数)”指定调用父类的有参构造器,不然就会报错。
class Base{//此代码编译报错
public Base(String s){
System.out.print("B");
}
}
public class Derived extends Base{
public Derived (String s) {
//super(s);//正确的代码应该有这个
System.out.print("D");
}
public static void main(String[] args){
new Derived("C");
}
}
3.static(静态的)
1. static可以用来修饰:属性、方法、代码块、内部类
2. 使用static修饰属性:静态变量(或类变量)
2.1 属性:按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)
实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性,当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量,当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
2.2 static修饰属性的其他说明:
2.2.1 静态变量随着类的加载而加载,可以通过”类.静态变量”的方式进行调用
类名.方法()
public class InvokeMethod{
public static void main(String[] args){
InvokeMethod.t2();
}
public static void t2(){
}
}
2.2.2 静态变量的加载要早于对象的创建
2.2.3 由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中。
// static声明的属性被所有对象所共享
private static int init = 1001;// 目前,内存当中只有唯一的一份init,
private int init_ = 1002;//每个对象都有一份init_;
2.2.4 类变量 实例变量
类 yes no
对象 yes yes
3.使用static修饰方法:静态方法(不允许被重写!)
A.随着类的加载而加载,可以通过”类.静态方法”的方式进行调用
B. 静态方法 非静态方法
类 yes no
对象 yes yes
C.静态方法中,只能调用静态的方法或属性
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
class Circle {
private static int total;// 记录创建圆的个数
public static int getTotal() {// 属性是static,则操作属性的方法也是static;
return total;
}
}
静态属性举例:System.out;Math.PI;
4.static注意点:
4.1 在静态的方法内,不能使用this关键字、super关键字
4.2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。
4.3 static家族可以互相访问
5.开发中,如何确定一个属性是否要声明为static的?
> 属性是可以被多个对象所共享的,不会随着对象的不同而不同的
> 类中的常量也常常声明为static
开发中,如何确定一个方法是否要声明为static的?
> 操作静态属性的方法,通常设置为static的
> 工具类中的方法,习惯上声明为static的,比如:Math、Arrays、Collections
6.static代码块
用途:形成静态代码块以优化程序性能(由于它只会在类的加载时执行一次)
class Person{
private Date birthDate;
public Person(Date brithDate){
this.birthDate = birthDate;
}
boolean isBornBoomer(){
Date startDate = Date.valueOf("1946-1-1");
Date endDate = Date.valueOf("1964-12-31");
return brithDate.compareTo(startDate) >= 0 && brithDate.compareTo(endDate) < 0;
}
}
isBornBoomer是用来这个人是否是1946-1964年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和brithDate两个对象,造成了空间浪费 ,改成这样会更好:
class Person{
private Date birthDate;
private static Date startDate,endDate;
static{
Date startDate = Date.valueOf("1946-1-1");
Date endDate = Date.valueOf("1964-12-31");
}
public Person(Date brithDate){
this.birthDate = birthDate;
}
boolean isBornBoomer(){
return brithDate.compareTo(startDate) >= 0 && brithDate.compareTo(endDate) < 0;
}
}
7. static能作用于局部变量吗?
在Java中切记:static是不允许用来修饰局部变量。不为什么,这是Java语法的规定。
public void test(){
static int a = 1;//会报异常
}
理由: (看到别人的好介绍)
A.局部变量最好不要设成静态变量,局部变量是有生命周期的,用完后JAVA很快就回收资源了;如果设成静态变量,那JAVA咋莫回收被其占用的内存
B.在方法里面定义的变量是局部变量,就是说他有一定的作用范围和生命周期,就只能在方法里面使用而不能将其扩展到别的地方,这个变量在方法结束后就会被回收器回收,就不再存在了 ,而你要强制将其加上static就是要把它的作用范围扩展到整个类,这就与你开始定义这个变量时违背了,这是语法上的错误
C.static变量是给类用的。这样类初始化的时候,就会给static进行初始化;如果你在方法里面定义一个static,这时候编译器就不知道你这个变量咋莫初始化了,这个是和java的设计相关的。java全是面向对象设计的,单独一个方法不能持有一块空间。
D.一个类中,一个static变量只会有一个内存空间,虽然有多个类实例,但这些类实例中的这个static变量会共享同一个内存空间,所以声明为static的变量实质上就是全局变量。所以static不能修饰局部变量。此外,局部变量是存放在栈中的,程序运行完立即释放,他只能在定义它的方法内部使用,所以不用static修饰符。
8.关于static修饰内部类在(JAVA类即成员那片博客里介绍了)
4.final(最终的)
1.final 可以用来修饰的结构:类、方法、变量
2.final 用来修饰一个类:此类不能被其它类所继承。
比如:String类、System类、StringBuffer类(这些类的功能很全,基本不用再扩充)
3.final 用来修饰方法:表明此方法不可以被重写
比如:Object类中getClass();
4.final 用来修饰变量:此时的“变量”就称为是一个常量;常量建议大写,每个单词之间采用下划线连接
4.1 final修饰属性:可以考虑赋值的位置有:显示初始化、代码块中初始化、构造器中初始化
注意:final修饰的实例变量,系统不负责赋默认值,要求程序员必须手动赋值;这个手动赋值,在变量后面可以,在代码块、构造器中也可以;但是final修饰的变量,系统不负责默认初始化赋值,方法中也不可以(因为在JVM加载过程中,构造器是加载的最后一道关卡,构造器调完对象就出生了若此时还未赋值,那就没意义了,方法加载的太晚)
class finalTest{
final int WIDTH = 0;//显式初始化
final int LEFT;
final int RIGHT;
{
LEFT = 1;//代码块中初始化
}
public finalTest(){
RIGHT = 2;//构造器中初始化
}
public finalTest(int n){
RIGHT = n;//如果多个构造器构成重载,则每个构造器必须被赋值
}
}
4.2 final修饰局部变量:
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参,一旦赋值以后,就只能在方法体内使用此实参,但不能进行重新赋值。
class finalTest{
public void show(){
final int NUM = 10;//常量
//NUM += 20;//错误,常量不能被操作
}
public void show(final int num){
//num = 20;//错误,final修饰的形参只能被调用,不能被重新赋值
}
}
static final用来修饰属性:全局变量(接口中用的多)
public static final double PI = 3.1415926;
一道面试题:
byte b1 = 1,b2 = 2,b3,b6,b8;
final byte b4 = 4,b5 = 6,b7 = 9;
b3 = b1 + b2;//A
b6 = b4 + b5;//B
b8 = b1 + b4;//C
b7 = b2 + b5;//D
只有B是对的
b1和b2是byte变量,在存储都会转为int
b3 = (byte)(b1 + b2);
final修饰的属性,不光值不能变,类型也不能变
final byte b4 = 4,b5 = 6,b7 = 9;//不会被编译器转为int
5.abstract(抽象的)
abstract可以用来修饰的结构:类、方法
1.abstract修饰类:抽象类
1.1 此类不能被实例化
1.2 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
1.3 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
2.abstract修饰方法:抽象方法
2.1 抽象方法只有方法的声明,没有方法体
public abstract void eat();//抽象方法
2.2 包含抽象方法的类,一定是一个抽象类,反之,抽象类中可以没有抽象方法的
2.3 若子类重写了父类中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修 饰
abstract使用上的注意点:
1.abstract不能用来修饰:属性、构造器等结构
2.abstract不能用来修饰私有方法(声明为private的方法不能被重写)、静态方法(不能被重写)、final的方法(不能被重写)、final的类
6.interface(接口)和implements
接口的使用(用于实现功能!!!!!!!!)
1.接口使用interface来定义
2.Java中,接口和类是并列的两个结构
3.如何定义接口:定义接口中的成员
3.1 JDK7及以前,只能定义全局常量和抽象方法(不能定义变量)
>全局常量:public static final的,但是书写时,可以省略不写(接口中的变量,本质上都是static的,而且是final类型的,不管你加不加static修饰)
>抽象方法:public abstract的
3.2JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
// 静态方法
public static void method1() {
System.out.println("CompareA:北京");
}
// 默认方法
public default void method2() {
System.out.println("CompareA:上海");
}
4.接口中不能定义构造器!意味着接口不可以实例化。
5.Java开发中,接口通过让类去实现(implements)的方式来使用。
如果实现类覆盖率接口中的所有抽象方法,则此实现类就可以实例化。
如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类;即接口的实现类必须 实现接口的全部方法
6.Java类可以实现多个接口—>弥补了Java单继承性的局限性
格式:class AA extends BB implements CC,DD,EE
7.接口与接口之间可以继承(通过extends),而且可以多继承
8.接口的具体使用,体现多态性(这里详细介绍了关于创建接口匿名实现类的对象)
public class USBTest {
public static void main(String[] args) {
Computer com = new Computer();
//1.创建了接口的非匿名实现类的非匿名对象
Flash flash = new Flash();//接口USB不能造对象,只能造实现类的对象,多态性的体现
com.transferData(flash);
//2.创建了接口的非匿名实现类的匿名对象
com.transferData(new Printer());
//3.创建了接口的匿名实现类的非匿名对象
USB phone = new USB() {
@Override
public void start() {
System.out.println("手机开始工作");
}
@Override
public void stop() {
System.out.println("手机结束工作");
}
};
com.transferData(phone);
//4.创建了接口的匿名实现类的匿名对象
com.transferData(new USB() {
@Override
public void start() {
System.out.println("mp3开始工作");
}
@Override
public void stop() {
System.out.println("mp3结束工作");
}
});
}
}
interface USB{
//常量:定义了长、宽、最大最小的传输速度等
void start();
void stop();
}
class Computer{
public void transferData(USB usb) {
usb.start();//执行结果:U盘开启工作
System.out.println("具体传输数据的细节");
usb.stop();//执行结果:U盘结束工作
}
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盘开启工作");
}
@Override
public void stop() {
System.out.println("U盘结束工作");
}
}
class Printer implements USB{
@Override
public void start() {
System.out.println("打印机开启工作");
}
@Override
public void stop() {
System.out.println("打印机结束工作");
}
}
9.接口,实际上可以看作是一种规范
接口的使用
1.接口使用上也满足多态性
2.接口,实际上就是定义了一种规范
接口中只有public权限,接口中只有全局常量和抽象方法
只有在接口中abstract static final public 都可以省略掉!!!(阿里规约中,定义接口,尽量简洁!)
public interface IMessage{
//全局常量
int NUM = 100;
//抽象方法
String msg();
}
3.开发中,体会面向接口编程!
java8关于接口的5个新规范
public class SubClassTest {
public static void main(String[] args) {
SubClass s = new SubClass();
// 知识点1:接口中定义的静态方法,只能通过接口来调用。
CompareA.method1();
// 知识点2:通过实现类的对象,可以调用接口中的默认方法。
// 如果实现类重写了接口中的默认方法,调用时,仍然用的是重写以后的方法
s.method2();
// 知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法。
// 那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。-->类优先原则
// 知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法。
// 那么在实现类没有重写此方法的情况下,报错:---->接口冲突。
// 那就需要我们必须在实现类中重写此方法
// 5在下面
s.method3();
}
}
public interface CompareA {
// 静态方法
public static void method1() {
System.out.println("CompareA:北京");
}
// 默认方法
public default void method2() {
System.out.println("CompareA:上海");
}
default void method3() {
System.out.println("CompareA :上海");
}
}
public interface CompareB {
default void method3() {
System.out.println("CompareB:上海");
}
}
class SubClass extends SuperClass implements CompareA, CompareB {
@Override
public void method2() {
System.out.println("SubClass:上海");
}
@Override
public void method3() {
System.out.println("SubClass:深圳");
}
// 知识点5:如何在子类(或实现类)的方法中调用父类,接口中被重写的方法
public void myMethod() {
method3();// 调用自己定义的重写的方法
super.method3();// 调用的是父类中声明的
// 调用接口中的默认方法
CompareA.super.method3();
CompareB.super.method3();
}
}
接口仍然不能直接实例化对象,必须通过子接口来向上转型。
public class MessageImpl immplements IMessage,INews{
@Override
public String msg(){
return "hello bit";
}
@Override
public void getNews(){
System.out.println("hello news~");
}
public static void main(String[] args){
IMessage message = new MessageImpl();
System.out.println(message.msg());
}
}
message只能调用msg方法
不能调用getNews – (INews接口定义)
要想使用getNews方法,就需要父接口间的相互转换。
INews news = (INews)message;
public static void main(String[] args){
IMessage message = new MessageImpl();
System.out.println(message.msg());
INews news = (INews)message;
news.getNews();
}
父类/父接口 父引用 = new 子类实例();
到底能调用啥方法,看前面父类/父接口中定义了啥方法
调用方法长啥样子,要看new的是那个子类。
接口的使用者与实现者
电脑是USB接口的使用者而非实现者(类的内部拥有USB接口,USB的实现者)
关于接口的一种规约:(个人感觉没人用)
一般接口的命名使用I开头和类做区分
子类实现接口可以使用impl结尾,表示是接口的子类。
//interface定义了IMessage
public interface IMessage{
//全局常量
public static final int NUM = 100;
//抽象方法
public String msg();
}
public class MessageImpl implements IMessage{
@Override
public String msg() {
return "hello bit";
}
}
7.instanceof(也可实现接口)
背景:有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法,子类特有的属性和方法不能调用。
开发中主要用向上转型(多态)
如何才能调用子类特有的属性和方法?
答:向下转型,使用强制类型转换符。
Man m1 = (Man)p2;
m1.earnMoney();
//使用强转时,可能出现ClassCastException的异常
Woman w1 = (Woman)p2;//p2是Man;两者并列关系
w1.goShopping();
instanceof关键字的使用
a instanceof A: 判断对象a是否是类A的实例;如果是,返回true,如果不是,返回false.
使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型,如果返回false,不进行向下转型。
如果 a instanceof A 返回true,则 a instanceof B也返回true.
其中,类B时类A的子类。
Person p2 = new Man();
if(p2 instanceof Woman){//Woman和Man无关系,不会输出
Woman w1 = (Woman)p2;
w1.goShopping();
system.out.println("********Woman***********");
}
if(p2 instanceof Woman){//满足子父类关系,可以输出
Woman m2 = (Woman)p2;
m2.earnMoney();
system.out.println("********Man***********");
}
if(p2 instanceof Person){//满足子父类关系,可以输出
system.out.println("********Person***********");
}
if(p2 instanceof Object){//满足子父类关系,可以输出
system.out.println("********Object***********");
}
向下转型中的几个常见问题:
//问题一:编译时通过,运行时不通过//这种情况就要加instanceof判断
//情况A:
Person p3 = new Woman();
Man m3 = (Man)p3;
//情况B:
Person p4 = new Person();
Man m4 = (Man)p4;//不能强转为其子类
//问题二:编译通过,运行也通过
Object obj = new Woman();
Person p = (Person)obj;//开发中可以这样
//问题三:编译不通过
Man m5 = new Woman();//报错原因:类型不匹配
//这种方式可以骗过编译器,让其编译时通过,但运行时,报错:类型不匹配
Object o = new Woman();
Man m6 = (Man)o;
向上转型(多态)和向下 转型的总结:
向上转型:参数统一化,使用父类引用,无论是那个子类,都能调用父类中已经定义好的方法,具体表现为啥样,就看子类方法覆写的内容了 => 对象的多态性
运行时多态性体现:
向上转型是在子类和父类间天然发生的is a关系:Dog is an Animal
能调用的方法要看父类,此时引用是父类的引用,只有在父类中定义了相关方法才能使用
到底调用的是谁要看子类是否覆写,若子类覆写了这个方法,则调用的一定是子类覆写后的方法,
向下转型
Student stu = (Student)o;
若此时要调用只有Student(子类)类中才具备的方法或属性时,就需要向下转型,将父类引用的外衣脱掉,还原为子类引用。
此时是进行Student对象的比较,比较Student类中的name和age属性,这俩属性是Student独有的,就需要向下转型还原为Student引用
看到的好的解释的博客(不一定正确,但思想可以):当一个类继承了另一个类,子类中没有父类的方法时。用子类的对象调用方法时,会首先在子类中查找,如果子类中没有该方法,再到父类中查找。
当一个方法只在父类中定义时,调用该方法时会使用父类中的属性。
如果该方法中又调用了其他方法,那么还是按照之前的顺序,先在子类中查找,再在父类中查找。
8.import(导包)
1.在源文件中显式的使用import机构导入制定包下的类、接口
2.生命在包的声明和类的声明之间
3.如果需要导入多个结构,则并列写出即可
4.可以使用”xxx.*”的方式,表示可以导入xxx包下所有的结构
5.如果使用的类或接口是java.lang包下定义的,则可以省略import结构
6.如果使用的类或接口是本包下定义的,则可以省略import结构
7.如果在源文件中,使用了不同剥下的同名的类,则必须至少有一个类需要以全类名的方式显示。
8.使用”xxx.*”的方式表明可以调用xxx包下的所有的结构,但是如果使用的是xxx子包下的结构,则仍需显式导入
9.import static:导入指定类或接口中的静态结构:属性或方法。
补充:
1.(abstract不能与static关键字共存)abstract不能被static修饰,因为抽象方法要被重写、而static和子类占不到边。反过来也一样static方法一定不能被abstract方法修饰,static不属于对象而属于类,static方法可以被类直接调用(抽象方法需要被实现才能被调用,也就是重写其方法),这样注定了static方法一定有方法体,不能是没有方法体的抽象方法
2.abstract不能与final关键字共存,因为final关键字修饰的类是不能被继承的。
3.
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/110977.html