有关相互扩展的类中的覆盖方法的问题。

时间:2018-09-22 19:56:50

标签: java dynamic static overwrite

我正在学习Java考试,并且对静态和动态类型有疑问。

我有4个班级:A,B,C和Main。

public class A {
   private void tell(){
   System.out.println("AA");
    }
}

public class B extends A {
public void tell(){
    System.out.println("BB");
}
}

public class C extends B {

}

public class Main{
public static void main(String[] args) {
    A c = new C();       
    c.tell();
}

}

我的建议是:输出应为“ BB”,因为c具有动态类型C。由于C没有“ tell”方法,所以使用上层B的方法,该方法打印“ BB”。

但是结果是一个错误,因为Java在A中寻找“ tell”。在A中它当然找不到,因为在那里被声明为priavte。但是为什么它看起来在A中,虽然只有它的静态类型是A,但是它的动态类型是C?

1 个答案:

答案 0 :(得分:2)

您会收到一个错误消息,因为在编译时,编译器不知道将放置在A中的实际实例,因此,当编译器看到import * as React from 'react'; import { Component, ComponentClass, ComponentType } from 'react'; import { DocumentReference, Query, CollectionReference, DocumentSnapshotExpanded, QuerySnapshotExpanded } from './firemodel'; import { firestore } from 'firebase'; import { pick, forEach, isEqual, isFunction } from 'lodash'; import { expandDocSnapshot, expandQuerySnapshot } from 'modules/providers/util'; import SmartLoader from 'modules/atoms/SmartLoader'; type FirestoreQueryable<DataType> = | DocumentReference<DataType> | Query<DataType> | CollectionReference<DataType>; type FirestoryQueryableFunction< DataType, Props > = ( firestore: firestore.Firestore, props: Props, ) => Promise<FirestoreQueryable<DataType>>; type QueryConfigEntry<Props> = FirestoreQueryable<any> | FirestoryQueryableFunction<any, Props>; type QueryConfig<Props> = { [queryName: string]: QueryConfigEntry<Props>; }; type FirestoreQueryableExpanded<Props, QE extends QueryConfigEntry<Props>> = QE extends FirestoreQueryable<any> ? FirestoreQueryableExpanded1<QE> : QE extends FirestoryQueryableFunction<any, Props> ? FirestoreQueryableExpanded1<ReturnType<QE>> : unknown; type FirestoreQueryableExpanded1<QE extends FirestoreQueryable<any>> = QE extends CollectionReference<infer DataType> | Query<infer DataType> ? QuerySnapshotExpanded<DataType> : QE extends DocumentReference<infer DataType> ? DocumentSnapshotExpanded<DataType> : unknown; interface WithFirestoreConfig<Props, PL extends keyof Props, Q extends QueryConfig<Props>> { /** Object containing the queries to be provided to WrappedComponent. * The queryName used is also the prop name the snapshot is passed in. */ queries: Q; /** A list of props to whitelist passing to WrappedComponent. * Configs without a list will whitelist all props */ props?: PL[]; /** Loading config items */ loading?: { /** Number of ms after which to display the loading icon */ delay?: number; /** Number of ms after which to display the timeout message */ timeout?: number; }; } type WithFirestoreHoC = <Props>() => <PL extends keyof Props, Q extends QueryConfig<Props>>( config: WithFirestoreConfig<Props, PL, Q>, ) => ( WrappedComponent: ComponentType<WithFirestore<Props, Q> & Pick<Props, PL>>, ) => ComponentClass<Props, { error: Error; queries: {}; loaded: boolean }>; const withFirestore: WithFirestoreHoC = // An extra function call is needed so that callers can specify Props and // still have PL and Q inferred. It can be removed when // https://github.com/Microsoft/TypeScript/issues/10571 is implemented. <Props extends {}>() => // Note: if `props` is not passed, there will be no inference for PL and it // will default to its constraint, which is exactly the behavior we want as // far as typing is concerned. <PL extends keyof Props, Q extends QueryConfig<Props>>({ queries, props: propPickList, loading: { delay = 200, timeout = 0 } = {}, }: WithFirestoreConfig<Props, PL, Q>) => WrappedComponent => class WithFirestoreConnect extends Component<Props, { error: Error; queries: WithFirestore<Props, Q>; loaded: boolean }> { subscriptions: { [queryName: string]: ReturnType<FirestoreQueryable<any>['onSnapshot']>; } = {}; state = { error: null as Error, queries: {} as WithFirestore<Props, Q>, loaded: false, }; componentDidMount() { this.restartSubscription(); } cancelSubscriptions = () => { forEach(this.subscriptions, unsubscribe => unsubscribe()); this.subscriptions = {}; }; restartSubscription = () => { // Open questions: // - figuring out when all loaded (use a promise?) this.cancelSubscriptions(); forEach(queries, async (q: QueryConfigEntry<Props>, key) => { let ref: FirestoreQueryable<any>; if (isFunction(q)) { // The fact that this is an async/await means that we can // create dependent queries within our FirestoreQueryableFunction ref = await q(firestore(), this.props); } else { // Narrowing is not working for some reason. ref = q as FirestoreQueryable<any>; } if (ref instanceof firestore.DocumentReference) { this.subscriptions[key] = ref.onSnapshot( snap => { this.setState({ queries: Object.assign({}, this.state.queries, {[key]: expandDocSnapshot(snap)}), }); }, err => { console.error(JSON.stringify(err)); this.setState({ error: err }); this.cancelSubscriptions(); }, ); } else if ( ref instanceof firestore.CollectionReference || ref instanceof firestore.Query ) { let ref2: {onSnapshot(os: (snap: firestore.QuerySnapshot) => void, oe: (err: Error) => void): () => void; } = ref; this.subscriptions[key] = ref2.onSnapshot( snap => { this.setState({ queries: Object.assign({}, this.state.queries, {[key]: expandQuerySnapshot(snap)}), }); }, err => { console.error(JSON.stringify(err)); this.setState({ error: err }); this.cancelSubscriptions(); }, ); } }); }; componentDidUpdate(prevProps: Props) { if (!isEqual(this.props, prevProps)) { this.restartSubscription(); } } componentWillUnmount() { this.cancelSubscriptions(); } render() { if (!this.state.loaded || this.state.error) { return ( <SmartLoader error={this.state.error} timeout={timeout} delay={delay} /> ); } const whitelistedProps = propPickList ? pick(this.props, propPickList) : this.props; // Unsure what's wrong here ~ Matt let WrappedComponent2 = WrappedComponent as any; return <WrappedComponent2 {...whitelistedProps} {...this.state.queries} />; } }; export type WithFirestore<Props, Q extends QueryConfig<Props>> = { [queryName in keyof Q]: FirestoreQueryableExpanded<Props, Q[queryName]>; } export default withFirestore; // EXAMPLE interface MyDoc { y: number } declare let myDocRef: DocumentReference<MyDoc>; declare let myCollRef: CollectionReference<MyDoc>; let wrapped = withFirestore<{x: string}>()({ queries: { myDoc: myDocRef, myColl: myCollRef }, })((props) => { return <>{props.myDoc.data.y + props.myColl.docs[props.x].data.y}</>; }); 时,他只看了c.tell()类确实没有一种可行的A方法。

了解这一点的一种方法是使用此示例:

tell()

您可以看到前两行都可以(根据您当前的思维逻辑)。 public class A { private void tell(){ System.out.println("AA"); } } public class B extends A { public void tell(){ System.out.println("BB"); } } public class C extends A { } public class Main{ public static void main(String[] args) { A b = new B(); b.tell(); A c = new C(); c.tell(); } } 的方法为B,因此tell()应该可以调用b。但是,如果将完全相同的赋值与没有tell()方法的C的另一个子类一起使用,则您的逻辑将失败。 tell()A都具有C方法,因此程序突然调用了一个不存在或无法访问的方法。