此处将为大家介绍关于Java“关键字”浅析的详细内容,并且为您解答有关java关键字详解的相关问题,此外,我们还将为您介绍关于1、final关键字2、static关键字3、匿名对象4、内部类5、包的声
此处将为大家介绍关于Java “关键字” 浅析的详细内容,并且为您解答有关java关键字详解的相关问题,此外,我们还将为您介绍关于1、final 关键字 2、static 关键字 3、匿名对象 4、内部类 5、包的声明与访问 6、访问修饰符 7、代码块、Emacs专业模式-关键字“特殊字符”和“一个字符”关键字、Java final 关键字、Java static 关键字的有用信息。
本文目录一览:- Java “关键字” 浅析(java关键字详解)
- 1、final 关键字 2、static 关键字 3、匿名对象 4、内部类 5、包的声明与访问 6、访问修饰符 7、代码块
- Emacs专业模式-关键字“特殊字符”和“一个字符”关键字
- Java final 关键字
- Java static 关键字
Java “关键字” 浅析(java关键字详解)
1 普通关键字注意事项
Java 中取消了 goto 的使用(C 语言中有 goto 关键字),取而代之的是循环标签。循环标签请见本人另文。
- 也就是说,在 Java 中,goto 与 const 是保留字,不可以作为标识符使用。
- 而 true、false 是布尔型的直接量,null 是引用类型的直接量,也不可以作为标识符使用。
- “$” 该符号在定义标识符时应尽量避免使用,因为编译器中隐藏使用该字符,若使用,可能出现不可避免的错误。
- 定义标识符时,若使用除 null 以外的 ASCII 字符,则标识符的最大长度:65536,即 216-1。
- Unicode 转义的处理时期要早于转义序列与八进制转义。
- Unicode 转义的处理时期是在编译器将程序解析成各符号之前就进行的。
参考一下代码:
1 //char c=''\u000a'';
上述代码虽然被注释,但是编译时仍会出现错误,它等价于:
1 //char c=''
2 '';
试想,该代码肯定不会编译通过啊!
2 final 关键字浅谈
final 关键字
使用 final 关键字做标识符有 “最终的” 含义。
final 可以修饰类、方法、属性和变量
- final 修饰类,则该类不允许被继承。
- final 修饰方法,则该方法不循序被覆盖(重写)。
- final 修饰属性,则该类的属性不会进行隐式的初始化(类的初始化属性必须有值)或在构造方法中赋值(但只能选其一)。
- final 修饰变量,则该变量的值只能被赋一次,即变为常量。
1、final 关键字 2、static 关键字 3、匿名对象 4、内部类 5、包的声明与访问 6、访问修饰符 7、代码块
01final关键字概念
* A: 概述
继承的出现提高了代码的复用性,并方便开发。但随之也有问题,有些类在描述完之后,不想被继承,
或者有些类中的部分方法功能是固定的,不想让子类重写。可是当子类继承了这些特殊类之后,
就可以对其中的方法进行重写,那怎么解决呢?
要解决上述的这些问题,需要使用到一个关键字final,final的意思为最终,不可变。
final是个修饰符,它可以用来修饰类,类的成员,以及局部变量。
02final修饰类义
* A: final 修饰类
final修饰类不可以被继承,但是可以继承其他类。
* B: 案例
class Yy {}
final class Fu extends Yy{} //可以继承Yy类
class Zi extends Fu{} //不能继承Fu类
03final修饰方法
* A: final修饰方法
final修饰的方法不可以被覆盖,但父类中没有被final修饰方法,子类覆盖后可以加final。
* B: 案例
class Fu {
// final修饰的方法,不可以被覆盖,但可以继承使用
public final void method1(){}
public void method2(){}
}
class Zi extends Fu {
//重写method2方法
public final void method2(){}
}
04final修饰局部变量
* A:修饰基本数据类型变量
final修饰的变量称为常量,这些变量只能赋值一次
* B:案例1
final int i = 20;
i = 30; //赋值报错,final修饰的变量只能赋值一次
* C: 修饰引用数据类型
引用类型的变量值为对象地址值,地址值不能更改,但是地址内的对象属性值可以修改
* D: 修饰引用数据类型
final Person p = new Person();
Person p2 = new Person();
p = p2; //final修饰的变量p,所记录的地址值不能改变
p.name = "小明";//可以更改p对象中name属性值
p不能为别的对象,而p对象中的name或age属性值可更改。
05final修饰成员变量
* A: 修饰成员变量
修饰成员变量,需要在创建对象前赋值,否则报错。(当没有显式赋值时,多个构造方法的均需要为其赋值。)
* B: 案例
class Demo {
//直接赋值
final int m = 100;
//final修饰的成员变量,需要在创建对象前赋值,否则报错。
final int n;
public Demo(){
//可以在创建对象时所调用的构造方法中,为变量n赋值
n = 2016;
}
}
06static的概念
* A:概念
当在定义类的时候,类中都会有相应的属性和方法。而属性和方法都是通过创建本类对象调用的。
当在调用对象的某个方法时,这个方法没有访问到对象的特有数据时,方法创建这个对象有些多余。
可是不创建对象,方法又调用不了,这时就会想,那么我们能不能不创建对象,就可以调用方法呢?
可以的,我们可以通过static关键字来实现。static它是静态修饰符,一般用来修饰类中的成员。
==============================第二节课开始====================================
07static修饰的对象特有数据
* A:特点1:
被static修饰的成员变量属于类,不属于这个类的某个对象。
(也就是说,多个对象在访问或修改static修饰的成员变量时,其中一个对象将static成员变量值进行了修改,
其他对象中的static成员变量值跟着改变,即多个对象共享同一个static成员变量)
* B: 代码演示
class Demo {
public static int num = 100;
}
class Test {
public static void main(String[] args) {
Demo d1 = new Demo();
Demo d2 = new Demo();
d1.num = 200;
System.out.println(d1.num); //结果为200
System.out.println(d2.num); //结果为200
}
}
08static的内存图
* A: 略
参考day13_source 静态的内存图.jpg
09static注意事项_静态不能直接调用非静态
* A: 注意事项
被static修饰的成员可以并且建议通过类名直接访问。
* B: 访问静态成员的格式:
类名.静态成员变量名
类名.静态成员方法名(参数)
对象名.静态成员变量名 ------不建议使用该方式,会出现警告
对象名.静态成员方法名(参数) ------不建议使用该方式,会出现警告
* C: 代码演示
class Demo {
//静态成员变量
public static int num = 100;
//静态方法
public static void method(){
System.out.println("静态方法");
}
}
class Test {
public static void main(String[] args) {
System.out.println(Demo.num);
Demo.method();
}
}
10static静态的使用场景
* A: 使用场景
static可以修饰成员变量和成员方法。
什么时候使用static修饰成员变量?
加static修饰成员的时候,这个成员会被类的所有对象所共享。一般我们把共性数据定义为静态的变量
什么时候使用static修饰成员方法?
静态的方法只能访问静态的成员,如果静态方法中引用到了静态的其他成员,那么这个方法需要声明为静态的方法。
11对象中的静态调用
* A: 对象的静态调用
在多态中,非静态编译看父类,运行看子类,父类没有编译失败。
但多态中的静态方法,编译看父类,运行仍然看父类。因为静态和对象没有关系,属于静态绑定。
* B: 举例
public class Test{
public static void main(String[] args){
Fu f = new Zi();
f.show(); //父类的引用和父类的方法绑定,和对象无关,不会在运行时动态的执行子类特有的方法。
}
}
12定义静态常量
* A: 静态常量
开发中,我们想在类中定义一个静态常量,通常使用public static final修饰的变量来完成定义。
此时变量名用全部大写,多个单词使用下划线连接。
* B: 定义格式:
public static final 数据类型 变量名 = 值;
* C: 如下演示:
class Company {
public static final String COMPANY_NAME = "传智播客";
public static void method(){
System.out.println("一个静态方法");
}
}
当我们想使用类的静态成员时,不需要创建对象,直接使用类名来访问即可。
System.out.println(Company.COMPANY_NAME); //打印传智播客
Company.method(); // 调用一个静态方法
* D: 注意:
接口中的每个成员变量都默认使用public static final修饰。
所有接口中的成员变量已是静态常量,由于接口没有构造方法,所以必须显示赋值。可以直接用接口名访问。
interface Inter {
public static final int COUNT = 100;
}
访问接口中的静态变量
Inter.COUNT
==============================第三节课开始====================================
13匿名对象
* A:匿名对象的概述
* 匿名对象是指创建对象时,只有创建对象的语句,却没有把对象地址值赋值给某个变量。
* B:案例
public class Person{
public void eat(){
System.out.println();
}
}
创建一个普通对象
Person p = new Person();
创建一个匿名对象
new Person();
* C: 匿名对象的特点
a:创建匿名对象直接使用,没有变量名。
new Person().eat() //eat方法被一个没有名字的Person对象调用了。
b:匿名对象在没有指定其引用变量时,只能使用一次。
new Person().eat(); 创建一个匿名对象,调用eat方法
new Person().eat(); 想再次调用eat方法,重新创建了一个匿名对象
c:匿名对象可以作为方法接收的参数、方法返回值使用
class Demo {
public static Person getPerson(){
//普通方式
//Person p = new Person();
//return p;
//匿名对象作为方法返回值
return new Person();
}
public static void method(Person p){}
}
class Test {
public static void main(String[] args) {
//调用getPerson方法,得到一个Person对象
Person person = Demo.getPerson();
//调用method方法
Demo.method(person);
//匿名对象作为方法接收的参数
Demo.method(new Person());
}
}
14内部类
* A: 内部类的概述
将类写在其他类的内部,可以写在其他类的成员位置和局部位置,这时写在其他类内部的类就称为内部类。
其他类也称为外部类。
* B: 什么时候使用内部类
在描述事物时,若一个事物内部还包含其他可能包含的事物,比如在描述汽车时,汽车中还包含这发动机,
这时发动机就可以使用内部类来描述。
class 汽车 { //外部类
class 发动机 { //内部类
}
}
* C: 内部类的分类
内部类分为成员内部类与局部内部类。
我们定义内部类时,就是一个正常定义类的过程,同样包含各种修饰符、继承与实现关系等。
在内部类中可以直接访问外部类的所有成员。
15成员内部类的调用格式
* A: 格式
成员内部类,定义在外部类中的成员位置。与类中的成员变量相似,可通过外部类对象进行访问
* B: 定义格式
class 外部类 {
修饰符 class 内部类 {
//其他代码
}
}
* C: 访问方式
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
* D: 成员内部类代码演示
class Body {//外部类,身体
private boolean life= true; //生命状态
public class Heart { //内部类,心脏
public void jump() {
System.out.println("心脏噗通噗通的跳")
System.out.println("生命状态" + life); //访问外部类成员变量
}
}
}
访问内部类
public static void main(String[] args) {
//创建内部类对象
Body.Heart bh = new Body().new Heart();
//调用内部类中的方法
bh.jump();
}
16成员内部类的同名变量调用
* A: 代码实现
public class Outer {
int i = 1;
class Inner {
int i = 2;
public void inner(){
int i = 3;
System.out.println(Outer.this.i);
}
}
}
17局部内部类
* A 局部内部类,定义在外部类方法中的局部位置。与访问方法中的局部变量相似,可通过调用方法进行访问.
* B 定义格式
class 外部类 {
修饰符 返回值类型 方法名(参数) {
class 内部类 {
//其他代码
}
}
}
* C 访问方式
在外部类方法中,创建内部类对象,进行访问
* D 局部内部类代码演示
定义类
class Party {//外部类,聚会
public void puffBall(){// 吹气球方法
class Ball {// 内部类,气球
public void puff(){
System.out.println("气球膨胀了");
}
}
//创建内部类对象,调用puff方法
new Ball().puff();
}
}
访问内部类
public static void main(String[] args) {
//创建外部类对象
Party p = new Party();
//调用外部类中的puffBall方法
p.puffBall();
}
==============================第四节课开始====================================
18匿名内部类
* A: 概述
内部类是为了应对更为复杂的类间关系。查看源代码中会涉及到,而在日常业务中很难遇到,这里不做赘述。
最常用到的内部类就是匿名内部类,它是局部内部类的一种。
定义的匿名内部类有两个含义:
临时定义某一指定类型的子类
定义后即刻创建刚刚定义的这个子类的对象
* B: 本质
匿名内部类的本质是一个实现了接口或继承了某个类的子类匿名对象.
* C: 案例
public interface Smoking {
public abstract void smoking();
}
/*
* 实现类,实现接口 重写接口抽象方法,创建实现类对象
* class XXX implements Smoking{
* public void smoking(){
*
* }
* }
* XXX x = new XXX();
* x.smoking();
* Smoking s = new XXX();
* s.smoking();
*
* 匿名内部类,简化问题: 定义实现类,重写方法,建立实现类对象,合为一步完成
*/
测试类:
public class Test {
public static void main(String[] args) {
//使用匿名内部类
/*
* 定义实现类,重写方法,创建实现类对象,一步搞定
* 格式:
* new 接口或者父类(){
* 重写抽象方法
* };
* 从 new开始,到分号结束
* 创建了接口的实现类的对象
*/
new Smoking(){
public void smoking(){
System.out.println("人在吸烟");
}
}.smoking();
}
}
19匿名内部类_2
* A: 匿名内部类案例演示
public abstract class Animal {
public abstract void eat();
public abstract void sleep();
}
测试代码
/*
* new Animal(){
public void eat(){
System.out.println("在吃饭");
}
public void sleep(){
System.out.println("在睡觉");
}
};
以上代码,就是Animal的子类的对象
多态性, 父类引用 = 子类的对象
*/
public class Test2 {
public static void main(String[] args) {
Animal a= new Animal(){
public void eat(){
System.out.println("在吃饭");
}
public void sleep(){
System.out.println("在睡觉");
}
};
a.eat();
a.sleep();
}
}
20包的概念
* A: 概念
java的包,其实就是我们电脑系统中的文件夹,包里存放的是类文件。
当类文件很多的时候,通常我们会采用多个包进行存放管理他们,这种方式称为分包管理。
在项目中,我们将相同功能的类放到一个包中,方便管理。并且日常项目的分工也是以包作为边界。
类中声明的包必须与实际class文件所在的文件夹情况相一致,即类声明在a包下,则生成的.class文件必须在a文件夹下,否则,程序运行时会找不到类。
* B 声明格式
通常使用公司网址反写,可以有多层包,包名采用全部小写字母,多层包之间用”.”连接
类中包的声明格式:
package 包名.包名.包名…;
如:黑马程序员网址itheima.com那么网址反写就为com.itheima
传智播客 itcast.cn 那么网址反写就为 cn.itcast
注意:声明包的语句,必须写在程序有效代码的第一行(注释不算)
代码演示:
package cn.itcast; //包的声明,必须在有效代码的第一行
import java.util.Scanner;
import java.util.Random;
public class Demo {}
* C: 包的访问
在访问类时,为了能够找到该类,必须使用含有包名的类全名(包名.类名)。
包名.包名….类名
如: java.util.Scanner
java.util.Random
cn.itcast.Demo
带有包的类,创建对象格式:包名.类名 变量名 = new包名.类名();
cn.itcast.Demo d = new cn.itcast.Demo();
前提:包的访问与访问权限密切相关,这里以一般情况来说,即类用public修饰的情况。
类的简化访问
当我们要使用一个类时,这个类与当前程序在同一个包中(即同一个文件夹中),或者这个类是java.lang包中的类时通常可以省略掉包名,直接使用该类。
如:cn.itcast包中有两个类,PersonTest类,与Person类。我们在PersonTest类中,访问Person类时,由于是同一个包下,访问时可以省略包名,即直接通过类名访问 Person。
类名 变量名 = new类名();
Person p = new Person();
当我们要使用的类,与当前程序不在同一个包中(即不同文件夹中),要访问的类必须用public修饰才可访问。
package cn.itcst02;
public class Person {}
22导入包
* A:导入包
我们每次使用类时,都需要写很长的包名。很麻烦,我们可以通过import导包的方式来简化。
可以通过导包的方式使用该类,可以避免使用全类名编写(即,包类.类名)。
导包的格式:
import 包名.类名;
当程序导入指定的包后,使用类时,就可以简化了。演示如下
//导入包前的方式
//创建对象
java.util.Random r1 = new java.util.Random();
java.util.Random r2 = new java.util.Random();
java.util.Scanner sc1 = new java.util.Scanner(System.in);
java.util.Scanner sc2 = new java.util.Scanner(System.in);
//导入包后的方式
import java.util.Random;
import java.util.Scanner;
//创建对象
Random r1 = new Random();
Random r2 = new Random();
Scanner sc1 = new Scanner(System.in);
Scanner sc2 = new Scanner(System.in);
import导包代码书写的位置:在声明包package后,定义所有类class前,使用导包import包名.包名.类名;
23权限修饰符
* A 权限修饰符有哪些
在Java中提供了四种访问权限,使用不同的访问权限时,被修饰的内容会有不同的访问权限,
以下表来说明不同权限的访问能力:
public protected default private
同一类中 √ √ √ √
同一包中(子类与无关类) √ √ √
不同包的子类 √ √
不同包中的无关类 √
* B: 小结
归纳一下:在日常开发过程中,编写的类、方法、成员变量的访问
要想仅能在本类中访问使用private修饰;
要想本包中的类都可以访问不加修饰符即可;
要想本包中的类与其他包中的子类可以访问使用protected修饰
要想所有包中的所有类都可以访问使用public修饰。
注意:如果类用public修饰,则类名必须与文件名相同。一个文件中只能有一个public修饰的类。
24代码块
* A: 概述:
程序中用大括号括起来的代码叫代码块
* B: 分类
局部代码块 构造代码块 静态代码块 同步代码块
* C 局部代码块:
局部代码块是定义在方法或语句中
特点:
以”{}”划定的代码区域,此时只需要关注作用域的不同即可
方法和类都是以代码块的方式划定边界的
class Demo{
public static void main(String[] args) {
{
int x = 1;
System.out.println("普通代码块" + x);
}
int x = 99;
System.out.println("代码块之外" + x);
}
}
结果:
普通代码块1
代码块之外99
局部代码块作用:可以限定变量的声明周期.
* D: 构造代码块
构造代码块是定义在类中成员位置的代码块
特点:
优先于构造方法执行,构造代码块用于执行所有对象均需要的初始化动作
每创建一个对象均会执行一次构造代码块。
public class Person {
private String name;
private int age;
//构造代码块
{
System.out.println("构造代码块执行了");
}
Person(){
System.out.println("Person无参数的构造函数执行");
}
Person(int age){
this.age = age;
System.out.println("Person(age)参数的构造函数执行");
}
}
class PersonDemo{
public static void main(String[] args) {
Person p = new Person();
Person p1 = new Person(23);
}
}
* E: 静态代码块
静态代码块是定义在成员位置,使用static修饰的代码块。
特点:
它优先于主方法执行、优先于构造代码块执行,当以任意形式第一次使用到该类时执行。
该类不管创建多少对象,静态代码块只执行一次。
可用于给静态变量赋值,用来给类进行初始化。
public class Person {
private String name;
private int age;
//静态代码块
static{
System.out.println("静态代码块执行了");
}
}
* F: 同步代码块(多线程学习)
25总结
* 把今天的知识点总结一遍。
Emacs专业模式-关键字“特殊字符”和“一个字符”关键字
如何解决Emacs专业模式-关键字“特殊字符”和“一个字符”关键字
我想为emacs写一个主要模式,该模式应该对mml(音乐宏语言)关键字进行语法突出显示。我遵循了本教程:
http://ergoemacs.org/emacs/elisp_Syntax_coloring.html
这是我当前的代码 (在x-events下仍然有占位符,而我尚未调整并从本教程接手的x-functions):
;;
;; to install this mode,put the following lines
;; (add-to-list ''load-path "~/.emacs.d/lisp/")
;; (load "mml-mode.el")
;; into your init.el file and activate it with
;; ALT+X mml-mode RET
;;
;; create the list for font-lock.
;; each category of keyword is given a particular face
(setq mml-font-lock-keywords
(let* (
;; define several category of keywords
(x-keywords ''("#author" "#title" "#game" "#comment"))
(x-types ''("&" "?" "/" "=" "[" "]" "^" "<" ">"))
(x-constants ''("w" "t" "o" "@" "v" "y" "h" "q" "p" "n" "*" "!"))
(x-events ''("@" "@@" "ooo" "oooo"))
(x-functions ''("llAbs" "llAcos" "llAddToLandBanList"
"llAddToLandPassList"))
;; generate regex string for each category of keywords
(x-keywords-regexp (regexp-opt x-keywords ''words))
(x-types-regexp (regexp-opt x-types ''words))
(x-constants-regexp (regexp-opt x-constants ''words))
(x-events-regexp (regexp-opt x-events ''words))
(x-functions-regexp (regexp-opt x-functions ''words)))
`(
(,x-types-regexp . font-lock-type-face)
(,x-constants-regexp . font-lock-constant-face)
(,x-events-regexp . font-lock-builtin-face)
(,x-functions-regexp . font-lock-function-name-face)
(,x-keywords-regexp . font-lock-keyword-face)
)))
;;;###autoload
(define-derived-mode mml-mode text-mode "mml mode"
"Major mode for editing mml (Music Macro Language)"
;; code for Syntax highlighting
(setq font-lock-defaults ''((mml-font-lock-keywords))))
;; add the mode to the `features'' list
(provide ''mml-mode)
但是现在有两个问题:
首先,我有几个以#
开头的关键字(例如#author
)。但是#
似乎不起作用,因为如果我忽略它,它将起作用。
(x-keywords ''("#author"))
不起作用。
(x-keywords ''("author"))
可以,但是#
没有颜色。 @
也会发生相同的问题。可能还会与其他人一起,但我会尽力使他们一个接一个地工作。
第二个关键字似乎至少需要两个字母。
(x-keywords ''("o"))
不起作用。
(x-keywords ''("oo"))
有效。
但是我有几个“关键字”,其后仅是一个字母和两个(任意)十六进制数字(0-F)(例如o7D
)
如何指定找到一个字母的关键字? (最好与数字一起使用,但不是必须的)。
解决方法
两个问题都来自同一个问题:与正则表达式的构造方式有关:
(regexp-opt x-blabla ''words)
问题是''words
参数。这样做是将生成的正则表达式包含在\\<
... \\>
对中。根据{{3}},这些特殊字符类的定义如下:
\\<
matches the empty string,but only at the beginning of a word.
‘\\<’ matches at the beginning of the buffer only if a word-constituent
character follows.
\\>
matches the empty string,but only at the end of a word.
‘\\>’ matches at the end of the buffer only if the contents end with a
word-constituent character.
现在,“单词开头” 对Emacs意味着什么?那是取决于模式的。实际上,每个主要模式都定义了自己的Emacs manual,它是字符到语法代码的映射。有许多预定义的类,其中一个是"w"
,它将一个字符定义为单词的组成部分。通常,基于文本的模式将定义字母a...z
和A...Z
以具有语法代码"w"
,但也可能具有其他字符(例如连字符-
)。 / p>
好的,回到当前的问题。对于x-keywords
,根据您的定义,生成的x-keywords-regexp
为:
"\\\\<\\\\(#\\\\(?:author\\\\|comment\\\\|\\\\(?:gam\\\\|titl\\\\)e\\\\)\\\\)\\\\>"
(请注意,在字符串中,反斜杠是用于转义其他特殊字符(例如\\n
或\\t
的特殊字符。因此,为了对简单的反斜杠本身进行编码,则必须用另一个反斜杠将其引用。)
如上所述,我们在正则表达式的开头和结尾分别看到\\<
和\\>
(或者用字符串表示:"\\\\<"
和"\\\\>"
)。但是,正如我们刚刚了解的那样,为了使此正则表达式匹配,潜在匹配的第一个字符和最后一个字符都必须具有单词组成的语法。
字母并不重要,但是让我们通过键入 C-h s 来检查#
的语法代码:
The parent syntax table is:
C-@ .. C-h . which means: punctuation
TAB .. C-j which means: whitespace
C-k . which means: punctuation
C-l .. RET which means: whitespace
C-n .. C-_ . which means: punctuation
SPC which means: whitespace
! . which means: punctuation
" " which means: string
# . which means: punctuation
...
(显然被截断了。)
就在那里! #
字符 not 没有单词构成语法,被认为是标点符号。
但是我们可以通过将以下行放入您的主模式定义中来更改它:
(modify-syntax-entry ?# "w" mml-mode-syntax-table)
?#
是Emacs lisp中字符编码的方式(在C语言中考虑''#''
)。
关于问题的第二部分,为了匹配o75
之类的内容,我们必须做类似的事情:将所有数字定义为单词组成部分:
(modify-syntax-entry ''(?0 . ?9) "w" mml-mode-syntax-table)
但是,我们还需要编写适当的正则表达式来匹配此类关键字。 regexp本身并不困难:
"o[0-9A-F]\\\\{2\\\\}"
但是,放在哪里?由于它已经是一个正则表达式,因此我们不能简单地将其添加到x-keywords
,因为它是简单字符串的列表。
但是,我们可以通过将上述代码中的相应行更改为以下内容来将其连接为x-keywords-regexp
:
(x-keywords-regexp (concat (regexp-opt x-keywords ''words)
"\\\\|\\\\<[o][0-9A-F]\\\\{2\\\\}\\\\>"))
请注意string参数开头的"\\\\|"
,这是替代匹配项的regexp语法。
Java final 关键字
final关键字可以用来修饰类、方法、成员变量和局部变量。
修饰类
- final关键字修饰的类不能被继承。比如java.lang.String类就用final关键字修饰,java.lang.String不能被继承,只能用jdk提供的java.lang.String类
- final类中的成员变量可以根据需要进行final修饰
- final类中的所有成员方法隐式的指定为final方法
- 除非特殊考虑(确定以后不会用来继承或处于安全考虑不能继承),尽量不要把类设计为final类
修饰方法
- 锁定方法,防止任何继承类修改方法的含义
- 早起java版本中会将final方法转为内嵌调用,提升效率,如果方法国语庞大,可能感觉不到任务性能提升。最近版本中不需要使用final方法进行优化了
- 类的private方法隐式的指定为final方法
修饰变量
- 对于final修饰的基本数据类型的变量,数值一旦被初始化以后就不能被更改
- 对于final修饰的引用类型的变量,初始化以后内容是可以被更的
- 对于final修饰的引用类型的变量,初始化以后不能再指向另外一个对象
- 类的final成员变量必须在定义时或者构造器中初始化赋值,赋值以后不能再被赋值
- final修饰参数并不能阻止在方法中对此final参数的更改
- final修饰参数可以阻止此final参数指向另外一个对象
- 不用final修饰参数 此参数可以指向另外一个对象,但不会影响外部这个参数的内容(原因在于java采用的是值传递,对于引用变量,传递的是引用的值,也就是说让实参和形参同时指向了同一个对象,因此让形参重新指向另一个对象对实参并没有任何影响)
和static变量的区别
- static修饰的变量多个类对象是一样的,分配的一个内存空间,多个对象都用这一个就是一个值
- final修饰的变量初始化多个类对象的时候,都有各自的内存空间,如果赋值的是具体的值各个对象的这个final变量都一样,如果赋值的是随机的值,值相同的可能性非常小
匿名内部类
- 匿名内部类使用外部局部变量只能是final变量(保证局部变量和内部类中的变量数据一致性)
- 内部类中的使用的外部局部变量需要final修饰(保证局部变量和内部类中的变量数据一致性)
如有不正之处,欢迎指正。
Java static 关键字
static 关键字的用途
在《Java编程思想》P86页有这样一段话:
“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”
这段话虽然只是说明了static方法的特殊之处,但是可以看出static关键字的基本作用,简而言之,一句话来描述就是:
方便在没有创建对象的情况下来进行调用(方法/变量)。
很显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。
1. static方法
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。
但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的。举个简单的例子:
在上面的代码中,由于print2方法是独立于对象存在的,可以直接用过类名调用。假如说可以在静态方法中访问非静态方法/变量的话,那么如果在main方法中有下面一条语句:
MyObject.print2();
此时对象都没有,str2根本就不存在,所以就会产生矛盾了。同样对于方法也是一样,由于你无法预知在print1方法中是否访问了非静态成员变量,所以也禁止在静态成员方法中访问非静态成员方法。
而对于非静态成员方法,它访问静态成员方法/变量显然是毫无限制的。
因此,如果说想在不创建对象的情况下调用某个方法,就可以将这个方法设置为static。我们最常见的static方法就是main方法,至于为什么main方法必须是static的,现在就很清楚了。因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。
2. static变量
static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
static成员变量的初始化顺序按照定义的顺序进行初始化。
3. static代码块
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。
static 关键字误区
1. static关键字会改变类中成员的访问权限吗?
有些初学的朋友会将java中的static与C/C++中的static关键字的功能混淆了。在这里只需要记住一点:与C/C++中的static不同,Java中的static关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字。看下面的例子就明白了:
提示错误"Person.age 不可视",这说明static关键字并不会改变变量和方法的访问权限。
2. 能通过this访问静态成员变量吗?
虽然对于静态方法来说没有this,那么在非静态方法中能够通过this访问静态成员变量吗?先看下面的一个例子,这段代码输出的结果是什么?
public class Main {
static int value = 33;
public static void main(String[] args) throws Exception{
new Main().printValue();
}
private void printValue(){
int value = 3;
System.out.println(this.value);
}
}
这里面主要考察队this和static的理解。this代表什么?this代表当前对象,那么通过new Main()来调用printValue的话,当前对象就是通过new Main()生成的对象。而static变量是被对象所享有的,因此在printValue中的this.value的值毫无疑问是33。在printValue方法内部的value是局部变量,根本不可能与this关联,所以输出结果是33。在这里永远要记住一点:静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。当然不推荐这种访问方式,静态成员变量一般是通过类名加变量名访问,但是通过对象访问也没有问题。
3. static能作用于局部变量么?
在C/C++中static是可以作用域局部变量的,但是在Java中切记:static是不允许用来修饰局部变量。不要问为什么,这是Java语法的规定。
static 常见笔试题
1. 下面这段代码的输出结果是什么?
public class Test extends Base {
static {
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
{
System.out.println("test not static bolck");
}
public static void main(String[] args) {
new Test();
System.out.println("**********");
new Test();
}
}
public class Base {
static {
System.out.println("base static");
}
public Base() {
System.out.println("base constructor");
}
{
System.out.println("base not static bolck");
}
}
========================
base static
test static
base not static bolck
base constructor
test not static bolck
test constructor
**********
base not static bolck
base constructor
test not static bolck
test constructor
先来想一下这段代码具体的执行过程,在执行开始,先要寻找到main方法,因为main方法是程序的入口,但是在执行main方法之前,必须先加载Test类,而在加载Test类的时候发现Test类继承自Base类,因此会转去先加载Base类,在加载Base类的时候,发现有static块,便执行了static块。在Base类加载完成之后,便继续加载Test类,然后发现Test类中也有static块,便执行static块。在加载完所需的类之后,便开始执行main方法。在main方法中执行new Test()的时候会先调用父类的构造器,因为Base类中 非静态初始化块,所以执行完非静态在初始化块之后执行然后再调用自身的构造器。然后再调用Test的非静态初始化块,然后再调用Test的构造函数,由于Base Test 在第一次执行的时候已经加载,第二次运行的时候static块就不会在执行了 知会执行 非静态初始化块和构造函数。调用顺序跟第一次相同。
2. 这段代码的输出结果是什么?
public class Test {
Person person = new Person("Test");
static{
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
public static void main(String[] args) {
new MyClass();
}
}
class Person{
static{
System.out.println("person static");
}
public Person(String str) {
System.out.println("person "+str);
}
}
class MyClass extends Test {
Person person = new Person("MyClass");
static{
System.out.println("myclass static");
}
public MyClass() {
System.out.println("myclass constructor");
}
}
=================
test static
myclass static
person static
persion : Test
test constructor
persion : MyClass
myclass constructor
类似地,我们还是来想一下这段代码的具体执行过程。首先加载Test类(因为要执行的Main函数在Test类中),因此会执行Test类中的static块。接着执行new MyClass(),而MyClass类还没有被加载,因此需要加载MyClass类。在加载MyClass类的时候,发现MyClass类继承自Test类,但是由于Test类已经被加载了,所以只需要加载MyClass类,那么就会执行MyClass类的中的static块。在加载完之后,就通过构造器来生成对象。而在生成对象的时候,必须先初始化父类的成员变量,因此会执行Test中的Person person = new Person(),而Person类还没有被加载过,因此会先加载Person类并执行Person类中的static块,接着执行父类的构造器,完成了父类的初始化,然后就来初始化自身了,因此会接着执行MyClass中的Person person = new Person(),最后执行MyClass的构造器。
注:如果在Test类中添加初始化块
{
System.out.println("test not static");
}
则 test not static 将会出现在 test constructor之前 persion : Test之后
也就是说 初始化呢顺序 :
静态代码块 → 成员变量 → 初始化块 → 构造函数
3. 这段代码的输出结果是什么?
public class Test {
static{
System.out.println("test static 1");
}
public static void main(String[] args) {
}
static{
System.out.println("test static 2");
}
}
==============
static 1
static 2
虽然在main方法中没有任何语句,但是还是会输出,原因上面已经讲述过了。另外,static块可以出现类中的任何地方(只要不是方法内部,记住,任何方法内部都不行),并且执行是按照static块的顺序执行的。其实要执行Main方法,首先要加载Test类,所以执行了static块
今天的关于Java “关键字” 浅析和java关键字详解的分享已经结束,谢谢您的关注,如果想了解更多关于1、final 关键字 2、static 关键字 3、匿名对象 4、内部类 5、包的声明与访问 6、访问修饰符 7、代码块、Emacs专业模式-关键字“特殊字符”和“一个字符”关键字、Java final 关键字、Java static 关键字的相关知识,请在本站进行查询。
本文标签: