java入门 -- 面向对象关键字及内部类

1 static

我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量.

static可以用来修饰:属性、方法、代码块、内部类
在Java中切记:static是不允许用来修饰局部变量。
在static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构。

• 使用static修饰属性:静态变量(或类变量)

• 属性,按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)
• 实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
• 静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。
• 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用
• 静态变量的加载要早于对象的创建。
• 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。

• 使用static修饰方法:静态方法

• 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
• 静态方法中,只能调用静态的方法或属性
• 非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性

• static注意点:

• 在静态的方法内,不能使用this关键字、super关键字

• 开发中,如何确定一个属性是否要声明为static的?

• 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
• 类中的常量也常常声明为static
• 开发中,如何确定一个方法是否要声明为static的?
• 操作静态属性的方法,通常设置为static的
• 工具类中的方法,习惯上声明为static的。 比如:Math、Arrays、Collections

例子

public class Order {
	
	//static在加载的时候就会执行,故而会优于构造函数
	static int num = 0;
	String name = "qqqqqq";
	static String name2 = "wwwwwwwwwww";
	//这段调用函数执行一次,调用时 走类 寻找构造函数
	
	 static Order parentClass = new Order();
	
	Order(){
		System.out.println("这里是构造函数*************");
	}
	
	{
		System.out.println("name1:" + name);
		System.out.println("这里是块1============");
	}
	
	
	
	static {
		num += 1;
		System.out.println("parentClass.name:"+parentClass.name);
		System.out.println("这里是静态块*************" + num);
	}
	
	public static void main(String[] args) {
		// 构造函数的执行顺序问题 //构造的时候直接调用 占用了Static parentClass不能调用出static
		Order pa = new Order();
	}

我们可以看到Static代码块只被调用了一次,大家可以思考一下这个代码块是被pa 还是parentClass调用出来的,当pa构造的时候直接调用 占用了Static parentClass不能调用出static,也就是说当代码走到Order pa = new Order()的时候静态块,块1和构造函数已经被调用了一次,只是因为static Order parentClass = new Order()在Order内所以先输出出来。
调用顺序:static>代码块>构造函数
在这里插入图片描述

2 main

main方法作为程序的入口
JVM在运行程序的时候,会首先查找main方法。其中,public是权限修饰符,表明任何类或对象都可以访问这个方法,static表明main方法是一个静态方法,即方法中的代码是存储在静态存储区的,只要类被加载后,就可以使用该方法而不需要通过实例化对象来访问,可以直接通过类名.main()直接访问,JVM在启动的时候就是按照上述方法的签名(必须有public与static修饰,返回值为void,且方法的参数为字符串数组)来查找方法的入口地址,如果能找到就执行,找不到则会报错。void表明方法没有返回值,main是JVM识别的特殊方法名,是程序的入口方法。字符串数组参数args为开发人员在命令行状态下与程序交互提供了一种手段。

每一个类中都可以声名一个main方法,程序执行的时候指定一个入口即可


public class MainTest {
	
	
	public static void main(String[] args) {//入口
		
		Main.main(new String[100]);
		
		MainTest test = new MainTest();
		test.show();
		
	}	
	public void show(){
		
	}
}


class Main{
		
	public static void main(String[] args) {
	
		for(int i = 0;i < args.length;i++){
			args[i] = "args_" + i;
			System.out.println(args[i]);
		}
		
	}
	
}

main方法中的形参也可以作为与控制台交互的方式

package test14;

public class Main {
	public static void main(String[] args) {
           for (int i = 0; i < args.length; i++) {
			System.out.println(args[i]);
		}
	}
}

在这里插入图片描述
在控制台操作
在这里插入图片描述
面试题
此处,Something类的文件名叫OtherThing.java
class Something {
public static void main(String[] something_to_do) {
System.out.println(“Do something …”);
} }
上述程序是否可以正常编译、运行?
可编译
在这里插入图片描述
可运行
在这里插入图片描述

3 代码块

一个类中代码块若有修饰符,则只能被static修饰,称为静态代码块(static block),没有使用static修饰的,为非静态代码块。
静态代码块

• 可以有输出语句。
• 可以对类的属性、类的声明进行初始化操作。
• 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
• 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
• 静态代码块的执行要先于非静态代码块。
• 静态代码块随着类的加载而加载,且只执行一次。

非静态代码块

• 可以有输出语句。
• 可以对类的属性、类的声明进行初始化操作。
• 除了调用非静态的结构外,还可以调用静态的变量或方法。
• 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
• 每次创建对象的时候,都会执行一次。且先于构造器执行。

例如

package test14;public class Main {
	public static void main(String[] args) {
		System.out.println("total = " + Person.total);
		System.out.println("total = " + Person.total);
	}
}

class Person {
	public static int total;
	static {
		total = 100;
		System.out.println("in static block!");
	}
}

这个是其debug的样子可以看到执行第一个输出语句的时候执行了代码块,然后输出了
in static block!
total = 100
这是因为Person.total时执行了static代码块先输出了in static block!,然后才去调用total 的值。
在这里插入图片描述

3 final

在Java中声明类、变量和方法时,可使用关键字final来修饰,表示“最终的”

• final标记的类不能被继承。
• final标记的方法不能被子类重写。
• final标记的变量(成员变量或局部变量)即称为常量。名称大写,且只能被赋值一次
• final标记的成员变量必须在声明时或在每个构造器中或代码块中显式赋值,然后才能使用。
• final double MY_PI = 3.14;

在这里插入图片描述
错误信息:
最后一个局部变量x不能赋值。它必须为空并且不能使用复合赋值
在这里插入图片描述

4 抽象类与抽象方法

随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类

Java允许类设计者指定:超类声明一个方法但不提供实现,该方法的实现由子类提供。这样的方法称为抽象方法。有一个或更多抽象方法的类称为抽象类。

• 用abstract关键字来修饰一个类,这个类叫做抽象类。
• 用abstract来修饰一个方法,该方法叫做抽象方法。
• 抽象方法:只有方法的声明,没有方法的实现。以分号结束:
比如:public abstract void talk();
• 含有抽象方法的类必须被声明为抽象类。
• 抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
不能用abstract修饰变量、代码块、构造器;
不能用abstract修饰私有方法、静态方法、final的方法、final的类。

我们都知道,父类是将子类所共同拥有的属性和方法进行抽取,这些属性和方法中,有的是已经明确实现了的,有的还无法确定,那么我们就可以将其定义成抽象,在后日子类进行重用,进行具体化。这样,抽象类也就诞生了。
抽象类是为了把相同的但不确定的东西的提取出来,为了以后的重用。定义成抽象类的目的,就是为了在子类中实现抽象类。

public abstract class Role {//一个抽象类
	private String name;
	private int age;
	private String sex;
	public Role(String name, int age, String sex) {
		super();
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
	public Role() {
		super();
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	abstract void play() ;//一个抽象方法
	@Override
	public String toString() {
		return "Role [name=" + name + ", age=" + age + ", sex=" + sex + "]";
	}
		
	
}
public class Employee extends Role {
	private int salary;//薪水
	static int ID;
	public Employee(String name, int age, String sex, int salary) {
		super(name, age, sex);
		this.salary = salary;
	}
	public Employee(String name, int age, String sex) {
		super(name, age, sex);
	}
	public int getSalary() {
		return salary;
	}
	public void setSalary(int salary) {
		this.salary = salary;
	}
	public static int getID() {
		return ID;
	}
	public static void setID(int iD) {
		ID = iD;
	}
	
	public void play() {//实现抽象方法
		System.out.println("正在玩");
	}
	
	final public void sing() {
		System.out.println("我在唱歌!!");
	}
	
	public Employee(int salary) {
		super();
		this.salary = salary;
		System.out.println("super");
	}
	@Override
	public String toString() {
		return "Employee [salary=" + salary + "]";
	}
}

5 接口(interface)

有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
一般常量值和抽象方法定义在接口中
接口的特点

• 用interface来定义。
• 接口中的所有成员变量都默认是由public static final修饰的。
• 接口中的所有抽象方法都默认是由public abstract修饰的。
• 接口中没有构造器。
• 接口采用多继承机制。

说明:

• 定义Java类的语法格式:先写extends,后写implements
class SubClass extends SuperClass implements InterfaceA{ }
• 一个类可以实现多个接口,接口也可以继承其它接口。
• 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
• 接口的主要用途就是被实现类实现。(面向接口编程)
• 与继承关系类似,接口与实现类之间存在多态性
• 接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义(JDK7.0及之前),而没有变量和方法的实现。

抽象类和接口的区别
在这里插入图片描述

public class USBTest {
	public static void main(String[] args) {
		
		Computer com = new Computer();
		//1.创建了接口的非匿名实现类的非匿名对象
		Flash flash = new Flash();
		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结束工作");
			}
		});
	}
}

class Computer{
	
	public void transferData(USB usb){//USB usb = new Flash();
		usb.start();
		
		System.out.println("具体传输数据的细节");
		
		usb.stop();
	}
	
	
}

interface USB{
	//常量:定义了长、宽、最大最小的传输速度等
	
	void start();
	
	void stop();
	
}

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("打印机结束工作");
	}
	
}

若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。因为此时遵守:类优先原则。接口中具有相同名称和参数的默认方法会被忽略。

jdk8中的改进
Java 8中,你可以为接口添加静态方法和默认方法。从技术角度来说,这是完全合法的,只是它看起来违反了接口作为一个抽象定义的理念。

• 静态方法:使用 static 关键字修饰。可以通过接口直接调用静态方法,并执行其方法体。我们经常在相互一起使用的类中使用静态方法。你可以在标准库中找到像Collection/Collections或者Path/Paths这样成对的接口和类。
• 默认方法:默认方法使用 default 关键字修饰。可以通过实现类对象来调用。我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。比如:java 8 API中对Collection、List、Comparator等接口提供了丰富的默认方法

6 内部类

将一个类定义在另一个给类里面或者方法里面,这样的类就被称为内部类。

成员内部类

• 非static的成员内部类中的成员不能声明为static的,只有在外部类或static的成员内部类中才可声明static成员。
• 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式
• 成员内部类可以直接使用外部类的所有成员,包括私有的数据
• 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的

如何去调用内部或外部成员

package test14;

import test14.Outer.inOuter;

public class Outer {//外部类
	private int i =1;
	String s ="外部类";
       public class inOuter{//内部类
    	    String s="内部类";
    	  void test(){ 
    	  System.out.println(Outer.this.s);
			System.out.println(i);
			System.out.println(s);
    	  }		   
       }	

	public static void main(String[] args) {
		Outer o =new Outer();//创建外部对象
		inOuter i = o.new inOuter();//外部对象创建内部对象
			i.test();	
	}	
}

在这里插入图片描述
当内外部类有同名的成员变量或方法使用Outer.this.s,利用this关键词进行调用。

静态内部类

静态内部类不能直接访问外部类的非静态成员,但,可以通过new 外部类()成员的方式访问;

public class Outer {//外部类
	private int i =1;//
	 String s ="外部类";
       public static class inOuter{//内部类
//    	  String s="内部类";
    	  void test(){ 
    		 System.out.println(new Outer().s);
//			System.out.println(i);
//			System.out.println(s);
    	  }		   
       }	

	public static void main(String[] args) {
		Outer o =new Outer();
		inOuter i = new inOuter();//注意这里变化
			i.test();	
	}

在这里插入图片描述
当外部静态,内部静态且同名时,也可以通过这种方式进行调用。

方法内部类

方法内部类就是定义在外部类的方法中,方法内部类只在该方法内可以用;

class O {// 外部类
	private int i = 1;//
	static String s = "外部类";
     void test(){//方法内部类
    	 System.out.println("方法内部类");
	  class inOuter {// 内部类
		 String s = "内部类";
		void test() {
			System.out.println("调用方法内部类");
		}				
	}
//	  inOuter i =new inOuter();  //只有这里可以调用出方法内部类。
//	  i.test();
     }
}
public class Outer{
	public static void main(String[] args) {
	O o = new O();
	o.test();
}
}

去注释前
在这里插入图片描述
去注释后
在这里插入图片描述

匿名内部类

匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
所谓的匿名内部类就是一个没有显式的名字的内部类,在实际开发中,此种内部类用的是非常多的。
格式:

• new 父类构造器(实参列表)|实现接口(){
• //匿名内部类的类体部分
• }

匿名内部类的特点

• 匿名内部类必须继承父类或实现接口
• 匿名内部类只能有一个对象
• 匿名内部类对象只能使用多态形式引用

public class Outernm {
	public void method() {
		new Inner() {

			@Override
			public void info() {
				System.out.println("匿名内部类");
			}
			
		}.info(); //注意这里的操作
		
	}
	public static void main(String[] args) {
		Outernm o =new Outernm();
		o.method();
	}

}
interface Inner {
	public void info();
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
面向对象是一种程序设计的思想,它将程序中的数据和对数据的操作封装在一起,形成对象对象是类的一个实例,类定义了对象的属性和行为。在Java中,面向对象的概念包括类与对象的关系、封装、构造函数、this关键字、static关键字以及设计模式等方面。 设计模式是在软件设计中常用的解决问题的经验总结,它提供了一套可重用的解决方案。在Java中,单例设计模式是一种常见的设计模式之一,它保证一个类只有一个实例,并提供一个全局访问点。通过使用单例设计模式,可以确保在程序中只有一个对象实例被创建,从而节省了系统资源并提高了性能。 通过使用单例设计模式,可以实现以下效果: - 限制一个类只能有一个实例。 - 提供一个全局访问点,使其他对象可以方便地访问该实例。 - 保证对象的唯一性,避免多个对象的状态不一致。 在Java中,实现单例设计模式有多种方式,包括饿汉式、懒汉式、双重检测锁等。每种方式都有各自的特点和适用场景,开发者可以根据具体的需求选择合适的实现方式。设计模式是一种通用的解决问题的方法,它可以在面向对象的程序设计中提供灵活、可复用的解决方案。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [计算机后端-Java-Java核心基础-第15章 面向对象07 14. 设计模式与单例设计模式.avi](https://download.csdn.net/download/programxh/85435560)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [完整版Java全套入门培训课件 Java基础 03-面向对象(共18页).pptx](https://download.csdn.net/download/qq_27595745/21440470)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值