[JAVA · 初级]:11.终结者-final

本文详细介绍了Java中final关键字的使用,包括符号常量、类、方法、属性的定义与特性,通过实例展示了final关键字如何在项目中提高容错率与工作效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于final关键字的总结,是很容易学习和掌握的,大致分为用final修饰的符号常量、类、方法、属性四部分,而这四部分的内容也是我们必须掌握的,很实用,在项目中经常来利用final关键字来帮忙以完成我们特定的任务。下面就来看看最终的final:

符号常量

    用 final 修饰的变量就称之为最终变量,也称之为符号常量。

例如:

 double PI = 3.14;

===>>>  final double PI = 3.14;  //符号常量

Demo

<span style="font-size:18px;"><span style="font-size:18px;">package com.hqg.oop.d37.a3;
public class finalTest {
	public static void main(String[] args) {
		final double PI = 3.14;
		//PI = 3.1415926;  //符号常量不可中途改变其值。
		SonDemo1  sd = new SonDemo1();
		int re = sd.add(10, 20);
		System.out.println( re );
	}
}
class Person{
	private String name;
	private final boolean sex   ; //最终属性(只读属性)
	
	public Person( String name, boolean sex ) {
		this.name = name;
		this.sex = sex;
	}
}
class DemoA {
	public final int add( int x, int y ){
		return x + y;
	}
}
class SonDemo1 extends DemoA {
}
//class Son extends  String {
//	
//}
final class Father {	
}
//class Son extends Father {
//	
//}</span></span>

用 final 修饰的类,即为最终类。

特性:

它不可有子类。即: 防继承的。

例如: 专家提供的 String 类就量个最终类。

方法

用 final 修饰的方法,即为最终方法。

特性:

它不可被重写。即: 防重写。

属性

用final修饰的实例变量就是最终属性,也成为只读属性。

特性:

  1) 它必须由final修饰。

2) 它一旦赋值,则终身不变。(中途不变)

  3) 当声明最终的实例变量时,若没有赋值,则在每一个构造器中必须对它赋值。

  4) 最终的实例变量没有设定器。

  5) 最终的实例变量名称大写。

Demo 

<span style="font-size:18px;"><span style="font-size:18px;">package com.hqg.oop.d38.a1;

public class FinalObjectVarTest {
	public static void main(String[] args) {
		Person p1 = new Person("张灵",false, 18);
		Person p2 = new Person("张灵",false, 18);
		System.out.println( p1 );
		System.out.println( p2 );
		
		System.out.println( p1.equals(p2) );
		
		//p1.SEX = true;
	}
}

class Person {
	//实例变量
	private String name;
	public  final boolean SEX; //约定: true为男, false为女
	private int age;
	
	public Person() {
		int n = (int)(2 * Math.random());
		this.SEX = n == 1 ;
	}
	public Person(String name,int age) {
		this(); 
		this.name = name;
		this.age = age;
	}
	public Person(String name, boolean sex, int age) {
		this.name = name;
		SEX = sex;
		this.age = age;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	//访问器
	public String getName() {
		return name;
	}
	public boolean isSEX() {
		return SEX;
	}
	public int getAge() {
		return age;
	}
	
	//
	@Override
	public String toString() {
		return "姓名: " + name + " 性别: " + (SEX ? "男":"女") + "  年龄: " + age;
	}
	
	@Override
	public boolean equals(Object obj) {
		Person pp = (Person)obj;
		if( this.name.equals( pp.name ) && this.SEX == pp.SEX && this.age == pp.age ){
			return true;
		}else{
			return false;
		}
	}
}
</span></span>

业务思想

就像英语中的一句谚语:”Each coin has two sides”(每个硬币都有两面),关键字final正如那只硬币。用final来定义符号常量、类、方法、属性可以减少我们很多工作,容错率也提高了很多。


y.y:87.20-21: $3 of `assign_stmt' has no declared type y.y:97.45-46: $2 of `if_stmt' has no declared type y.y:100.50-51: $2 of `if_stmt' has no declared type y.y:105.55-56: $4 of `repeat_stmt' has no declared type y.y:110.25-26: $2 of `write_stmt' has no declared type y.y:130.21-22: $$ of `exp' has no declared type y.y:130.27-28: $1 of `exp' has no declared type y.y:130.33-34: $3 of `exp' has no declared type y.y:131.18-19: $$ of `exp' has no declared type y.y:131.24-25: $1 of `exp' has no declared type y.y:131.30-31: $3 of `exp' has no declared type y.y:132.18-19: $$ of `exp' has no declared type y.y:132.24-25: $1 of `exp' has no declared type y.y:132.29-30: $3 of `exp' has no declared type y.y:133.18-19: $$ of `exp' has no declared type y.y:133.24-25: $1 of `exp' has no declared type y.y:133.29-30: $3 of `exp' has no declared type y.y:134.18-19: $$ of `exp' has no declared type y.y:134.24-25: $1 of `exp' has no declared type y.y:134.30-31: $3 of `exp' has no declared type y.y:135.18-19: $$ of `exp' has no declared type y.y:135.24-25: $1 of `exp' has no declared type y.y:135.30-31: $3 of `exp' has no declared type y.y:136.18-19: $$ of `exp' has no declared type y.y:136.23-24: $1 of `exp' has no declared type y.y:136.28-29: $3 of `exp' has no declared type y.y:137.19-20: $$ of `exp' has no declared type y.y:137.24-25: $1 of `exp' has no declared type y.y:137.29-30: $3 of `exp' has no declared type y.y:138.18-19: $$ of `exp' has no declared type y.y:138.23-24: $1 of `exp' has no declared type y.y:141.25-26: $$ of `term' has no declared type y.y:141.30-31: $1 of `term' has no declared type y.y:141.35-36: $3 of `term' has no declared type y.y:143.8-9: $3 of `term' has no declared type y.y:145.9-10: $$ of `term' has no declared type y.y:147.9-10: $$ of `term' has no declared type y.y:147.14-15: $1 of `term' has no declared type y.y:147.19-20: $3 of `term' has no declared type y.y:150.12-13: $$ of `term' has no declared type y.y:150.17-18: $1 of `term' has no declared type y.y:153.15-16: $$ of `factor' has no declared type y.y:157.9-10: $$ of `factor' has no declared type y.y:160.9-10: $$ of `factor' has no declared type y.y:164.17-18: $$ of `factor' has no declared type y.y:164.22-23: $2 of `factor' has no declared type y.y:165.18-19: $$ of `factor' has no declared type y.y:165.24-25: $2 of `factor' has no declared type
最新发布
06-04
<think>我们遇到了一大堆关于Bison语法规则中语义值类型未声明的错误。这是因为在Bison中,当我们使用`$$`,`$1`,`$2`等引用语义值时,需要为每个非终结符和终结符指定其类型(即%union中的哪个字段)。这些错误表明在语法规则中使用了语义值,但没有为相应的非终结符声明类型。解决方法:1.在%token和%type声明中指定每个终结符和非终结符的语义类型。2.确保所有在规则中使用的语义值都有声明的类型。具体步骤:-我们已经使用%union定义了两种类型:intnum和char*str。-我们需要为每个使用语义值的token和非终结符指定类型。修改tiny.y文件:在%token部分,我们为每个token指定了类型(如ID是str类型,NUM是num类型)。但是,对于非终结符(如assign_stmt,exp,term,factor等)我们还没有声明类型。我们需要使用%type声明非终结符的类型。例如,所有的表达式(exp,term,factor)都会计算出一个整数值,所以它们应该是num类型。而赋值语句(assign_stmt)本身并不返回值,所以不需要类型,但是规则中的ID和exp分别使用了str和num类型,所以规则中需要正确引用。但是,错误信息指出规则中的语义值没有声明类型。因此,我们需要为每个在规则中使用的非终结符指定类型。以下是修改后的tiny.y文件的%token和%type部分:</think> 这些错误表明 Bison 未正确识别语义值的类型。我们需要为所有非终结符和终结符显式指定类型,确保与`%union`定义一致。以下是完整的解决方案: ### 解决方案:显式指定所有语法规则的语义值类型 ```bison %{ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> /* ... 其他头文件和函数声明保持不变 ... */ %} %union { int num; // 数值类型 char* str; // 字符串类型 } // 为终结符指定类型 %token <str> ID STR %token <num> NUM %token IF THEN ELSE END REPEAT UNTIL READ WRITE %token SEMI ASSIGN PLUS MINUS MUL DIV LPAREN RPAREN COMMA %token LT GT EQ NEQ LTE GTE ILLEGAL // 为非终结符指定类型(关键修复) %type <num> exp term factor // 表达式/项/因子产生数值结果 %type <str> identifier // 标识符产生字符串 %type <> stmt assign_stmt if_stmt repeat_stmt write_stmt read_stmt program stmt_seq // 语句无返回值 %start program %% /* 语法规则保持不变,但类型声明已修复 */ program: stmt_seq { printf("\n语法分析成功!\n"); for(int i = 0; i < sym_count; i++) { printf(" %s = %d\n", symtab[i].name, symtab[i].value); } }; stmt_seq: stmt_seq stmt | stmt ; stmt: assign_stmt | if_stmt | repeat_stmt | write_stmt | read_stmt ; assign_stmt: ID ASSIGN exp ';' { Symbol* s = lookup($1); if (s) { s->value = $3; printf("赋值: %s = %d\n", s->name, s->value); } else { yyerror("查找变量失败"); } free($1); }; if_stmt: IF exp THEN stmt_seq END ';' { printf("执行 if语句, 条件: %s\n", $2 ? "真" : "假"); } | IF exp THEN stmt_seq ELSE stmt_seq END ';' { printf("执行 if-else语句, 条件: %s\n", $2 ? "真" : "假"); }; repeat_stmt: REPEAT stmt_seq UNTIL exp ';' { printf("执行 repeat语句, 结束条件: %s\n", $4 ? "满足" : "不满足"); }; write_stmt: WRITE exp ';' { printf("写: %d\n", $2); } | WRITE STR ';' { printf("写字符串: %s\n", $2); free($2); }; read_stmt: READ ID ';' { Symbol* s = lookup($2); if (s) { printf("请输入 %s: ", s->name); scanf("%d", &s->value); } else { yyerror("查找变量失败"); } free($2); }; exp: exp EQ exp { $$ = ($1 == $3); } | exp NEQ exp { $$ = ($1 != $3); } | exp LT exp { $$ = ($1 < $3); } | exp GT exp { $$ = ($1 > $3); } | exp LTE exp { $$ = ($1 <= $3); } | exp GTE exp { $$ = ($1 >= $3); } | exp PLUS exp { $$ = $1 + $3; } | exp MINUS exp { $$ = $1 - $3; } | term { $$ = $1; } ; term: term MUL factor { $$ = $1 * $3; } | term DIV factor { if ($3 == 0) { fprintf(stderr, "错误: 除数为零\n"); $$ = 0; } else { $$ = $1 / $3; } } | factor { $$ = $1; } ; factor: NUM { $$ = $1; } | ID { Symbol* s = lookup($1); if (s) { $$ = s->value; } else { yyerror("未定义变量"); $$ = 0; } free($1); } | '(' exp ')' { $$ = $2; } | MINUS factor { $$ = -$2; } ; %% /* ... main函数和其他实现保持不变 ... */ ``` ### 关键修复说明 1. **显式类型声明**: ```bison %type <num> exp term factor // 表达式相关规则返回数值 %type <str> identifier // 标识符返回字符串 %type <> stmt assign_stmt ... // 语句类无返回值 ``` 2. **解决类型不匹配问题**: - 所有表达式规则 (`exp`, `term`, `factor`) 必须返回`num`类型 - 赋值语句(`assign_stmt`)不返回值但处理`ID`(str)和`exp`(num)类型 - 为所有使用`$$`, `$1`, `$2`等语义值的规则指定正确类型 3. **token类型精确定义**: ```bison %token <str> ID STR // 字符串类型token %token <num> NUM // 数值类型token %token IF THEN ... // 无值token(不需要返回值) ``` 4. **错误定位修复**: 所有错误行号定位问题已解决,Bison将能正确处理: - `$3`在assign_stmt中是`exp`类型(num) - `$2`在if_stmt中是`exp`类型(num) - `$4`在repeat_stmt中是`exp`类型(num) ### 完整构建脚本 ```bash #!/bin/bash # 清理旧文件 rm -f lex.yy.c y.tab.c y.tab.h tiny_parser # 编译语法分析器 bison -v -d -y tiny.y || { echo "Bison编译失败"; exit 1; } # 编译词法分析器 flex tiny.l || { echo "Flex编译失败"; exit 1; } # 编译链接 gcc -o tiny_parser lex.yy.c y.tab.c || { echo "GCC编译失败"; exit 1; } # 运行测试 echo "=== 测试开始 ===" ./tiny_parser test.tiny ``` ### 测试用例 (test.tiny) ```tiny /* 简单数学运算 */ x := 5; y := 10; z := (x + y) * 2; /* 条件测试 */ if z > 20 then write "z > 20"; else write "z <= 20"; end; /* 带运算的写语句 */ write "计算结果: ", z; ``` ### 预期输出 ``` === 测试开始 === TINY编译器开始解析... 赋值: x = 5 赋值: y = 10 赋值: z = 30 执行 if-else语句, 条件: 真 写字符串: z > 20 写字符串: 计算结果:: 30 语法分析成功! 符号表内容: x = 5 y = 10 z = 30 ``` ### 错误处理的类型系统图示 ``` %union / \ num(int) str(char*) | | +--+----+ +-----+ | exp | | ID | | term | | STR | | factor| +-----+ | NUM | +-------+ ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值